<?php

namespace App\Kuafu\Mybank\Service;

use App\Exceptions\BaseException;
use App\Kuafu\Base\Service\BaseService;
use App\Kuafu\Mybank\Enum\MyBankWalletRecordEnum;
use App\Kuafu\Mybank\Model\MybankBatchNoRecordModel;
use App\Kuafu\Mybank\Model\MybankBillRecordBindModel;
use App\Kuafu\Mybank\Model\MybankBillRecordModel;
use App\Kuafu\Mybank\Model\MybankEntryModel;
use App\Kuafu\Mybank\Model\MybankFuyouBillRecordModel;
use App\Kuafu\Mybank\Model\MybankShopBindModel;
use App\Kuafu\Mybank\Model\MybankVostroBillModel;
use App\Kuafu\Mybank\Model\MybankWalletRecordModel;
use App\Kuafu\Mybank\Resources\MybankEntryDetailResource;
use App\Kuafu\Order\Enum\CodeEnum;
use App\Kuafu\Order\Model\OrderSplitModel;
use App\Kuafu\Pay\Model\PayStreamModel;
use App\Kuafu\Shop\Model\Shop;
use App\Kuafu\Shop\Resources\B\ShopSimpleResource;
use App\Kuafu\User\Model\UserUseServiceLogModel;
use App\Kuafu\WaiMai\Enum\WaiMaiDBEnum;
use App\Kuafu\WaiMai\Model\WaiMaiOrderModel;
use App\Library\FeiShu\SendFs;
use App\Library\KfHttp\OrmCurl;
use App\Remote\Mybank\MybankAccountRemote;
use App\Remote\Mybank\MybankCreateBatchRemote;
use App\Remote\Mybank\Remote;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Symfony\Component\HttpFoundation\Response as ResponseAlias;

class MybankService extends BaseService
{
    /**
     * 查看日志
     * @param string $userId
     * @param int $shopId
     * @return void
     */
    public static function addClickLog(string $userId, int $shopId = 0)
    {
        //添加钱包查看日志
        UserUseServiceLogModel::addLog($userId, $shopId, UserUseServiceLogModel::TYPE_WALLET);
    }

    /**
     * 钱包明细
     * @param string $userId 通过用户的id查询对应商户信息
     * @param int $shopId
     * @return array
     */
    public static function wallet(string $userId, int $shopId = 0): array
    {
        //添加钱包查看日志
        UserUseServiceLogModel::addLog($userId, $shopId, UserUseServiceLogModel::TYPE_WALLET);

        //添加日志
        self::addClickLog($userId, $shopId);
        $list      = [];
        $entryList = MybankEntryModel::getEntryIdByMobile($userId);
        if ($entryList) {
            foreach ($entryList as $v) {
                //网商门店入驻信息
                $data['entryInfo'] = $v;

                // 绑定门店
                $bindShopIds = MybankShopBindModel::getShopIdByEntryId($v['id']);

                // 仅查询定过货的门店
                $recordShopList = MybankWalletRecordModel::query()
                                                         ->select('shopId')
                                                         ->distinct()
                                                         ->where("merchantId", $v['merchantId'])
                                                         ->where('shopId', '>', 0)
                                                         ->get();

                if ($recordShopList) {
                    $shopIds  = $recordShopList->pluck('shopId')->all();
                    $shopList = Shop::query()
                                    ->with('waimaiShopMappings')
                                    ->select(['id', 'shopCode', 'name'])
                                    ->whereIn('id', $shopIds)
                                    ->get();

                    $data['shopList'] = collect(ShopSimpleResource::collection($shopList))->toArray();
                } else {
                    $data['shopList'] = [];
                }

                $data['balance'] = MybankWalletRecordModel::getBalance($v['merchantId']);//商户余额
                if ($v['status'] == MybankEntryModel::STATUS_3 && $v['withholdStatus'] == MybankEntryModel::WITHHOLD_STATUS_3) {//注册完成 去提现跳转
                    $jumpUrl = MybankEntryDetailResource::getLoginUrl($v['merchantId']);//获取商户登录接口
                } else {
                    $jumpUrl = MybankEntryDetailResource::getActiveUrl($v['status'], $v['registerStatus'],
                        $v['outMerchantId'], $v['principalMobile']);//获取激活链接
                }
                $data['jumpUrl'] = $jumpUrl;

                // 获取交易类型配置
                $data['tranTypeConfigList'] = enumToSelection(MyBankWalletRecordEnum::WALLET_RECORD_TYPE_TEXT);

                // 开通分账门店数量 ： 已绑定门店的数量
                $data['divideAccountsShopNum'] = count($bindShopIds);

                // 已通过钱包订货门店数量: 全部门店
                $data['walletOrderGoodsShopNum'] = MybankWalletRecordModel::query()
                                                                          ->where("merchantId", $v['merchantId'])
                                                                          ->where('shopId', '>', 0)
                                                                          ->distinct()
                                                                          ->count("shopId");

                $list[] = $data;
            }
        }
        return $list;
    }

    /**
     * 账单明细列表
     * @param $merchantId
     * @param $startDate
     * @param $endDate
     * @param $shopIds
     * @param $type
     * @param $pageSize
     * @param $pageNum
     * @param int $export
     * @return array
     */
    public static function billList(
        $merchantId,
        $startDate,
        $endDate,
        $shopIds,
        $type,
        $pageSize,
        $pageNum,
        $export = 0
    ): array {
        $paginator = MybankWalletRecordModel::query()
                                            ->with(['shopRel'])
                                            ->when($merchantId, function ($query) use ($merchantId) {
                                                $query->where('merchantId', $merchantId);
                                            })
                                            ->when($shopIds && is_array($shopIds), function ($query) use ($shopIds) {
                                                $query->whereIn('shopId', $shopIds);
                                            })
                                            ->when($type && is_array($type), function ($query) use ($type) {
                                                $query->whereIn('walletRecordType', $type);
                                            })
                                            ->when($startDate && $endDate,
                                                function ($query) use ($startDate, $endDate) {
                                                    $query->whereBetween('transDate',
                                                        [strtotime($startDate), strtotime($endDate) + 86400]);
                                                })
                                            ->where('isShow', MybankWalletRecordModel::SHOW_RECORD)
                                            ->orderBy('transDate', 'desc')
                                            ->when($export,
                                                function ($query) {
                                                    return $query->get();
                                                },
                                                function ($query) use ($pageSize, $pageNum) {
                                                    return $query->paginate($pageSize, ['*'], 'page', $pageNum);
                                                }
                                            );

        $list = $paginator->map(function (MybankWalletRecordModel $mybankWalletRecordModel) {
            return [
                'id'                   => $mybankWalletRecordModel->id,
                'shopId'               => $mybankWalletRecordModel->shopId,
                'shopCode'             => $mybankWalletRecordModel->shopRel ? $mybankWalletRecordModel->shopRel->shopCode : '',
                'shopName'             => $mybankWalletRecordModel->shopRel ? $mybankWalletRecordModel->shopRel->name : '',
                'transType'            => $mybankWalletRecordModel->transType,
                'displayTransType'     => $mybankWalletRecordModel->displayTransType,
                'transDate'            => $mybankWalletRecordModel->transDate ? date('Y-m-d H:i:s',
                    $mybankWalletRecordModel->transDate) : '',
                'transAmount'          => MybankWalletRecordModel::MAPPING_TRANS_TYPE_PLUS_MINUS[$mybankWalletRecordModel->transType] . bcdiv100($mybankWalletRecordModel->transAmount),
                'afterRemainingAmount' => bcdiv100($mybankWalletRecordModel->afterRemainingAmount),
                'remark'               => $mybankWalletRecordModel->remark,
                'transDesc'            => MyBankWalletRecordEnum::WALLET_RECORD_TYPE_TEXT[$mybankWalletRecordModel->walletRecordType] ?? '--',
                'platformType'         => $mybankWalletRecordModel->platformType,
                'platformTypeText'     => MybankWalletRecordModel::PLATFORM_TYPE_TEXT[$mybankWalletRecordModel->platformType],
                'transId'              => $mybankWalletRecordModel->transId,
            ];
        })->toArray();
        if ($export) {
            return ['list' => $list];
        }
        //支出
        $totalPayOutAmount = MybankWalletRecordModel::getSumAmount($startDate, $endDate,
            MybankWalletRecordModel::PAY_TRANS_TYPE, $shopIds, $merchantId, [], [],
            MybankWalletRecordModel::SHOW_RECORD, $type);

        // 提现支出
        $totalWithDrawAmount = MybankWalletRecordModel::getSumAmount($startDate, $endDate,
            MybankWalletRecordModel::INCOME_TRANS_TYPE, $shopIds, $merchantId, [], [],
            MybankWalletRecordModel::SHOW_RECORD, $type);
        //总收入金额
        $totalIncomeAmount = MybankWalletRecordModel::getSumAmount($startDate, $endDate,
            MybankWalletRecordModel::EARNING_TRANS_TYPE, $shopIds, $merchantId, [], [],
            MybankWalletRecordModel::SHOW_RECORD, $type);

        return [
            'pageNum'       => $paginator->currentPage(),
            'pageSize'      => $paginator->perPage(),
            'count'         => $paginator->total(),
            'list'          => $list,
            'total'         => [
                'totalWithDrawAmount' => bcdiv100($totalWithDrawAmount + $totalPayOutAmount),
                'totalIncomeAmount'   => bcdiv100($totalIncomeAmount),
            ],

            // 此字段废弃（配置信息移动到钱包明细接口返回） - 2023-12-19
            "transTypeText" => enumToSelection(MybankWalletRecordModel::MAPPING_TRANS_TYPE)
        ];
    }

    /**
     * 账单明细详情
     * @param int $id
     * @return array
     */
    public static function billDetail(int $id): array
    {
        $info = MybankWalletRecordModel::query()->with("shopRel")->where(['id' => $id])->first();
        if ($info) {
            return [
                'id'                   => $id,
                'transType'            => $info->transType,
                'displayTransType'     => $info->displayTransType,
                'transDate'            => $info->transDate ? date('Y-m-d H:i:s', $info->transDate) : '',
                'transAmount'          => bcdiv100($info->transAmount),
                'afterRemainingAmount' => bcdiv100($info->afterRemainingAmount),
                'transId'              => $info->transId,
                'remark'               => $info->remark,
                'transDesc'            => $info->transDesc,
                'transStatus'          => $info->status,
                'transStatusText'      => MybankWalletRecordModel::MAPPING_TRANS_STATUS[$info->status],
                'platformType'         => $info->platformType,
                'platformTypeText'     => MybankWalletRecordModel::PLATFORM_TYPE_TEXT[$info->platformType],
                'shopId'               => $info->shopId,
                'shopCode'             => $info->shopRel ? $info->shopRel->shopCode : "",
                'shopName'             => $info->shopRel ? $info->shopRel->name : "",
            ];
        }
        return [];
    }

    /**
     * 总账户入账记录
     * @param $startDate
     * @param $endDate
     * @param $pageSize
     * @param $pageNum
     * @param $export
     * @return array
     */
    public static function totalBillList($startDate, $endDate, $pageSize, $pageNum, $export): array
    {
        $paginator = MybankVostroBillModel::query()
                                          ->with(['mybankEntryRel', 'mybankOrderWithholdRecordRel'])
                                          ->where('type', MybankVostroBillModel::DEFAULT_TYPE)
                                          ->when($startDate && $endDate, function ($query) use ($startDate, $endDate) {
                                              $query->whereBetween('transferDate',
                                                  [strtotime($startDate), strtotime($endDate) + 86400]);
                                          })
                                          ->orderBy('transferDate', 'desc')
                                          ->orderBy('id', 'desc')
                                          ->paginate($pageSize, ['*'], 'page', $pageNum);

        return [
            'pageNum'  => $paginator->currentPage(),
            'pageSize' => $paginator->perPage(),
            'count'    => $paginator->total(),
            'list'     => $paginator->map(function (MybankVostroBillModel $myBankVostroBillModel) {

                return [
                    'id'           => $myBankVostroBillModel->id,
                    'merchantId'   => $myBankVostroBillModel->merchantId,
                    'merchantName' => $myBankVostroBillModel->mybankEntryRel->merchantName ?? "",
                    'transferDate' => $myBankVostroBillModel->transferDate ? date('Y-m-d H:i:s',
                        $myBankVostroBillModel->transferDate) : '',
                    'payerCardNo'  => $myBankVostroBillModel->payerCardNo,
                    'type'         => $myBankVostroBillModel->type,
                    'typeText'     => MybankVostroBillModel::MAPPING_TYPE[$myBankVostroBillModel->type],
                    'payeeCardNo'  => $myBankVostroBillModel->payeeCardNo,
                    'amount'       => bcdiv100($myBankVostroBillModel->amount),
                    'brokerage'    => bcdiv100($myBankVostroBillModel->mybankOrderWithholdRecordRel->totalAmount ?? 0),
                    'memo'         => $myBankVostroBillModel->memo,
                    'remark'       => $myBankVostroBillModel->remark,
                ];
            })
        ];
    }

    /**
     * @param $shopName
     * @param $merchantName
     * @param $merchantId
     * @return array
     */
    public static function getShopIdsByParameter($shopName, $merchantName = '', $merchantId = ''): array
    {
        $shopIds = $entryIds = [];
        if ($merchantName) {
            $entryIds = MybankEntryModel::query()
                                        ->where('merchantName', 'like', "%{$merchantName}%")
                                        ->get()
                                        ->pluck('id')
                                        ->toArray();
        }
        if ($merchantId) {
            $entryIds = MybankEntryModel::query()
                                        ->where('merchantId', $merchantId)
                                        ->get()
                                        ->pluck('id')
                                        ->toArray();
        }
        if ($entryIds) {
            $getShopIds = MybankShopBindModel::getShopIdByEntryId(0, $entryIds);
            $shopIds    = array_merge($shopIds, $getShopIds);
        }
        if ($shopName) {
            $getShopIds = shop::query()
                              ->when(!empty($shopName), function ($query) use ($shopName) {
                                  $query->where('name', 'like', '%' . $shopName . '%')
                                        ->orWhere('shopCode', 'like', '%' . $shopName . '%');
                              })
                              ->get()
                              ->pluck('id')
                              ->toArray();
            $shopIds    = array_merge($shopIds, $getShopIds);
        }
        return $shopIds;
    }

    /**
     * 后台商户收支明细
     * @param $type
     * @param $source
     * @param $merchantName
     * @param $merchantId
     * @param $startDate
     * @param $endDate
     * @param $shopName
     * @param $pageSize
     * @param $pageNum
     * @param $export
     * @return array
     */
    public static function expenseRecordList(
        $type,
        $source,
        $merchantName,
        $merchantId,
        $startDate,
        $endDate,
        $shopName,
        $pageSize,
        $pageNum,
        $export,
        $queryType
    ): array {
        $shopIds     = self::getShopIdsByParameter($shopName);
        $merchantIds = [];
        if ($merchantName) {
            $merchantIds = MybankEntryModel::query()
                                           ->where('merchantName', 'like', "%{$merchantName}%")
                                           ->get()
                                           ->pluck('merchantId')
                                           ->toArray();
        }
        $paginator = MybankWalletRecordModel::query()
                                            ->with(['shopRel', 'mybankEntryRel'])
                                            ->when($source != "" && $source >= 0, function ($query) use ($source) {
                                                $query->where('platformType', $source);
                                            })
                                            ->when($shopIds, function ($query) use ($shopIds) {
                                                $query->whereIn('shopId', $shopIds);
                                            })
                                            ->when($merchantId, function ($query) use ($merchantId) {
                                                $query->where('merchantId', $merchantId);
                                            })
                                            ->when($merchantIds, function ($query) use ($merchantIds) {
                                                $query->whereIn('merchantId', $merchantIds);
                                            })
                                            ->when($type, function ($query) use ($type) {
                                                $query->where('transType', $type);
                                            })
                                            ->when($startDate && $endDate,
                                                function ($query) use ($startDate, $endDate) {
                                                    $query->whereBetween('transDate',
                                                        [strtotime($startDate), strtotime($endDate) + 86400]);
                                                })
                                            ->when($queryType, function ($query) {
                                                $query->where(function ($query) {
                                                    // 只查询订货数据
                                                    $query->whereIn('walletRecordType', [
                                                        MyBankWalletRecordEnum::WALLET_RECORD_TYPE_OUT_GOODS,
                                                        MyBankWalletRecordEnum::WALLET_RECORD_TYPE_REFUND_GOODS
                                                    ])->orWhere('merchantId', Remote::getKfosBankMerchantId());
                                                });
                                            })
                                            ->orderBy('transDate', 'desc')
                                            ->orderBy('id', 'desc')
                                            ->when($export,
                                                function ($query) {
                                                    return $query->get();
                                                },
                                                function ($query) use ($pageSize, $pageNum) {
                                                    return $query->paginate($pageSize, ['*'], 'page', $pageNum);
                                                }
                                            );
        //总提现金额
        $totalWithDrawAmount = MybankWalletRecordModel::getSumAmount($startDate, $endDate,
            MybankWalletRecordModel::INCOME_TRANS_TYPE, $shopIds, $merchantId, $merchantIds, [],
            MybankWalletRecordModel::SHOW_RECORD, []);
        //总收入金额
        $totalIncomeAmount = MybankWalletRecordModel::getSumAmount($startDate, $endDate,
            MybankWalletRecordModel::EARNING_TRANS_TYPE, $shopIds, $merchantId, $merchantIds, [],
            MybankWalletRecordModel::SHOW_RECORD, []);
        //总支出金额
        $totalPayAmount = MybankWalletRecordModel::getSumAmount($startDate, $endDate,
            MybankWalletRecordModel::PAY_TRANS_TYPE, $shopIds, $merchantId, $merchantIds, [],
            MybankWalletRecordModel::SHOW_RECORD, []);
        //总充值金额
        $totalRechargeAmount = MybankWalletRecordModel::getSumAmount($startDate, $endDate,
            MybankWalletRecordModel::RECHARGE_TRANS_TYPE, $shopIds, $merchantId, $merchantIds, [],
            MybankWalletRecordModel::SHOW_RECORD, []);

        $list = $paginator->map(function (MybankWalletRecordModel $mybankWalletRecordModel) {
            return [
                'id'                   => $mybankWalletRecordModel->id,
                'shopId'               => $mybankWalletRecordModel->shopId,
                'shopCode'             => $mybankWalletRecordModel->shopRel ? $mybankWalletRecordModel->shopRel->shopCode : "",
                'shopName'             => $mybankWalletRecordModel->shopRel ? $mybankWalletRecordModel->shopRel->name : "",
                'merchantId'           => $mybankWalletRecordModel->merchantId,
                'merchantName'         => $mybankWalletRecordModel->mybankEntryRel->merchantName ?? "",
                'transId'              => $mybankWalletRecordModel->transId,
                'transType'            => $mybankWalletRecordModel->transType,
                'recordId'             => $mybankWalletRecordModel->recordId,
                'recordIdType'         => $mybankWalletRecordModel->recordIdType,
                'displayTransType'     => $mybankWalletRecordModel->displayTransType,
                'source'               => $mybankWalletRecordModel->platformType,
                'sourceTypeText'       => MybankWalletRecordModel::PLATFORM_TYPE_TEXT[$mybankWalletRecordModel->platformType],
                'transDate'            => $mybankWalletRecordModel->transDate ? date('Y-m-d H:i:s',
                    $mybankWalletRecordModel->transDate) : '',
                'transAmount'          => bcdiv100($mybankWalletRecordModel->transAmount),
                'afterRemainingAmount' => bcdiv100($mybankWalletRecordModel->afterRemainingAmount),
                'operator'             => '系统',
                'transDesc'            => $mybankWalletRecordModel->transDesc,
                'walletRecordType'     => $mybankWalletRecordModel->walletRecordType,
                'supplyChainBalance'   => bcdiv100($mybankWalletRecordModel->supplyChainBalance),
            ];
        });

        // 查询支付渠道号
        if (!empty($list)) {
            $list             = $list->toArray();
            $dealPayIdData    = [];
            $dealFefundIdData = [];
            $thirdPayNos      = [];
            $thirdRefundNos   = [];
            foreach ($list as $k => $v) {
                switch ($v['recordIdType']) {
                    case MybankWalletRecordModel::RECORD_ID_TYPE_WITHHOLD:
                        $dealPayIdData[] = $v['recordId'];
                        break;
                    case MybankWalletRecordModel::RECORD_ID_TYPE_REFUND:
                        $dealFefundIdData[] = $v['recordId'];
                        break;
                    case MybankWalletRecordModel::RECORD_ID_TYPE_CASHIER_PAY:
                        if ($v['walletRecordType'] == MyBankWalletRecordEnum::WALLET_RECORD_TYPE_OUT_GOODS) {// 订货支出
                            $thirdPayNos[] = $v['transId'];
                        } elseif ($v['walletRecordType'] == MyBankWalletRecordEnum::WALLET_RECORD_TYPE_REFUND_GOODS) {// 订货退款
                            $thirdRefundNos[] = $v['transId'];
                        }
                        break;
                }
            }

            // 支付数据
            $dealPayData = MybankOrderWithholdRecordService::getKfPayInfoByIds($dealPayIdData);

            // 退款数据
            $dealRefundIdData = MybankOrderWithholdRefundRecordService::getKfPayRefundInfoByIds($dealFefundIdData);

            // 网商收银台-支付数据
            $dealPayNoData = MybankCashierOrderService::getKfPayInfoByNos($thirdPayNos);

            // 网商收银台-退款数据
            $dealRefundNoData = MybankCashierOrderService::getKfPayRefundInfoByNos($thirdRefundNos);

            foreach ($list as $k => $item) {
                $kfPayNo      = 0;
                $outPayNo     = 0;
                $bizId        = '';
                $refundAmount = 0;
                switch ($item['recordIdType']) {
                    case MybankWalletRecordModel::RECORD_ID_TYPE_WITHHOLD:
                        $kfPayNo  = $dealPayData[$item['recordId']]['payNo'] ?? $kfPayNo;
                        $outPayNo = $dealPayData[$item['recordId']]['outTradeNo'] ?? $outPayNo;
                        $bizId    = $dealPayData[$item['recordId']]['bizId'] ?? $bizId;
                        break;
                    case MybankWalletRecordModel::RECORD_ID_TYPE_REFUND:
                        $outPayNo     = $dealRefundIdData[$item['recordId']]['outTradeNo'] ?? $outPayNo;
                        $refundAmount = bcdiv100($dealRefundIdData[$item['recordId']]['refundAmount'] ?? 0);
                        break;
                    case MybankWalletRecordModel::RECORD_ID_TYPE_CASHIER_PAY:
                        $outPayNo = $item['transId'];
                        if ($item['walletRecordType'] == MyBankWalletRecordEnum::WALLET_RECORD_TYPE_OUT_GOODS) {// 订货支出
                            $kfPayNo = $dealPayNoData[$item['transId']]['payNo'] ?? '';
                            $bizId   = $dealPayNoData[$item['transId']]['bizId'] ?? '';
                        } elseif ($item['walletRecordType'] == MyBankWalletRecordEnum::WALLET_RECORD_TYPE_REFUND_GOODS) {// 订货退款
                            $kfPayNo      = $dealRefundNoData[$item['transId']]['refundNo'] ?? '';
                            $outPayNo     = $dealRefundNoData[$item['transId']]['thirdPayNo'] ?? '';
                            $refundAmount = $item['transAmount'];
                        }
                        break;
                }
                $list[$k]['kfPayNo']          = $kfPayNo;
                $list[$k]['outPayNo']         = $outPayNo;
                $list[$k]['refundAmount']     = $refundAmount;
                $list[$k]['bizId']            = $bizId;
                $list[$k]['kfosPaymentFee']   = 0;
                $list[$k]['kfosKfPaymentFee'] = 0;
            }

            $list = collect($list);
        }

        // 批量查询订货手续费+修改原字段
        $list = self::batchQueryPaymentFee($list);

        if ($export) {
            return ['list' => $list->toArray()];
        }
        $total = [
            'totalWithDrawAmount' => bcdiv100($totalWithDrawAmount),//总提现金额
            'totalIncomeAmount'   => bcdiv100($totalIncomeAmount),  //入账总金额
            'totalRechargeAmount' => bcdiv100($totalRechargeAmount),//充值总金额
            'totalPayAmount'      => bcdiv100($totalPayAmount),     //支出总金额
        ];
        return [
            'pageNum'          => $paginator->currentPage(),
            'pageSize'         => $paginator->perPage(),
            'count'            => $paginator->total(),
            'list'             => $list,
            'total'            => $total,
            "platformTypeText" => enumToSelection(MybankWalletRecordModel::PLATFORM_TYPE_TEXT),
        ];
    }

    /**
     * 批量查询手续费
     *
     * @param Collection $list
     * @return Collection
     */
    public static function batchQueryPaymentFee(Collection $list): Collection
    {
        return $list
//            ->where('bizId', '!=', '')
            ->chunk(100)->map(function ($item) {
                $bizIds   = $item->pluck('bizId')->filter()->toArray();
                $kfosList = OrmCurl::queryOrderByCodes($bizIds)['data']['list'];
                $kfosList = array_column($kfosList, null, 'code');

                $itemArr = $item->toArray();
                foreach ($itemArr as $k => &$v) {
                    $v['kfosPaymentFee']   = $kfosList[$v['bizId']]['payment_fee'] ?? 0;
                    $v['kfosKfPaymentFee'] = $kfosList[$v['bizId']]['kf_payment_fee'] ?? 0;
                }

                return collect($itemArr);
            })->collapse();
    }

    /**
     * 后台商户收支记录-导出
     * @param $list
     * @param array $total
     */
    public static function exportExpenseRecordList($list, $total = [])
    {
        ini_set('max_execution_time', 100000);
        header("Content-Disposition: attachment; filename=" . urlencode('商户收支记录') . date('Y-m-d') . '.csv');

        // UTF8的BOM头
        $fd = fopen('php://output', 'w+');
        fwrite($fd, "\xEF\xBB\xBF");

        // 表头
        fputcsv(
            $fd, [
                '操作平台',
                '门店编号',
                '门店名称',
                '商户名称',
                '商户号',
                '交易金额',
                '夸父交易号',
                '网商交易号',
                '操作时间',
                '收支类型',
                '转账描述',
                '退款金额',
                '当前余额',
                '厦门万皮思供应链管理有限公司账户余额',
                '操作人',
            ]
        );

        $list->each(
            function ($item) use (&$fd) {
                fputcsv(
                    $fd, [
                        $item['sourceTypeText'],
                        $item['shopCode'],
                        $item['shopName'],
                        $item['merchantName'],
                        '`' . $item['merchantId'],
                        $item['transAmount'],
                        '`' . $item['kfPayNo'],
                        '`' . $item['outPayNo'],
                        $item['transDate'],
                        $item['displayTransType'],
                        $item['transDesc'],
                        $item['refundAmount'],
                        $item['afterRemainingAmount'],
                        $item['supplyChainBalance'],
                        $item['operator'],
                    ]
                );
                ob_flush();
                flush();
            }
        );

        fputcsv($fd, []);

        if (is_resource($fd)) {
            fclose($fd);
        }
        die;
    }

    /**
     * 后台财务清分列表
     * @param $startDate
     * @param $endDate
     * @param $billStartDate
     * @param $billEndDate
     * @param $source
     * @param $merchantName
     * @param $merchantId
     * @param $shopName
     * @param $flagDivision
     * @param $type
     * @param $pageSize
     * @param $pageNum
     * @param $export
     * @param $vostroBillId
     * @return array
     */
    public static function financeList(
        $startDate,
        $endDate,
        $billStartDate,
        $billEndDate,
        $source,
        $merchantName,
        $merchantId,
        $shopName,
        $flagDivision,
        $type,
        $pageSize,
        $pageNum,
        $export,
        $vostroBillId
    ): array {
        $shopIds   = self::getShopIdsByParameter($shopName, $merchantName, $merchantId);
        $paginator = MybankBillRecordModel::query()
                                          ->with(['shopRel'])
                                          ->leftJoin('mybank_bill_record_bind', 'mybank_bill_record_bind.billRecordId',
                                              '=', 'mybank_bill_record.id')
                                          ->where('mybank_bill_record.transType',
                                              MybankBillRecordModel::WITHDRAW_TRANS_TYPE)
                                          ->when($source > 0, function ($query) use ($source) {
                                              $query->where('mybank_bill_record.source', $source);
                                          })
                                          ->when($flagDivision >= 0, function ($query) use ($flagDivision) {
                                              $query->where('mybank_bill_record.flagDivision', $flagDivision);
                                          })
                                          ->when($type && $type >= 0, function ($query) use ($type) {
                                              $query->where('mybank_bill_record.transType', $type);
                                          })
                                          ->when($shopIds, function ($query) use ($shopIds) {
                                              $query->whereIn('mybank_bill_record.shopId', $shopIds);
                                          })
                                          ->when($startDate && $endDate, function ($query) use ($startDate, $endDate) {
                                              $query->whereBetween('mybank_bill_record_bind.completeTime',
                                                  [strtotime($startDate), strtotime($endDate) + 86400]);
                                          })
                                          ->when($billStartDate && $billEndDate,
                                              function ($query) use ($billStartDate, $billEndDate) {
                                                  $query->where('mybank_bill_record_bind.billStartAt', '>=',
                                                      strtotime($billStartDate));
                                                  $query->where('mybank_bill_record_bind.billEndAt', '<',
                                                      strtotime($billEndDate) + 86400);
                                              })
                                          ->when($vostroBillId > 0, function ($query) use ($vostroBillId) {
                                              $query->where('mybank_bill_record_bind.vostroBillId', $vostroBillId);
                                          })
                                          ->orderBy('mybank_bill_record.transDate', 'desc')
                                          ->orderBy('mybank_bill_record.id', 'desc')
                                          ->select([
                                              'mybank_bill_record.*',
                                              'mybank_bill_record_bind.vostroBillId',
                                              'mybank_bill_record_bind.merchantId',
                                              'mybank_bill_record_bind.completeTime',
                                              'mybank_bill_record_bind.billStartAt',
                                              'mybank_bill_record_bind.billEndAt'
                                          ])
                                          ->when($export,
                                              function ($query) {
                                                  return $query->get();
                                              },
                                              function ($query) use ($pageSize, $pageNum) {
                                                  return $query->paginate($pageSize, ['*'], 'page', $pageNum);
                                              }
                                          );
        if ($export) {
            $shopIds = array_column($paginator->toArray(), 'shopId');
        } else {
            $shopIds = array_column($paginator->items(), 'shopId');
        }
        $shopIds   = array_unique($shopIds);
        $entryList = [];
        if ($shopIds) {
            $entryList = MybankShopBindModel::getEntryByShopId($shopIds);//商户信息
            if ($entryList) {
                $entryList = $entryList->keyBy('shopId')->toArray();
            }
        }
        return [
            'pageNum'       => $paginator->currentPage(),
            'pageSize'      => $paginator->perPage(),
            'count'         => $paginator->total(),
            'list'          => $paginator->map(function (MybankBillRecordModel $mybankBillRecordModel) use ($entryList
            ) {
                return [
                    'id'                   => $mybankBillRecordModel->id,
                    'shopId'               => $mybankBillRecordModel->shopId,
                    'shopCode'             => $mybankBillRecordModel->shopRel ? $mybankBillRecordModel->shopRel->shopCode : "",
                    'shopName'             => $mybankBillRecordModel->shopRel ? $mybankBillRecordModel->shopRel->name : "",
                    'merchantId'           => $entryList[$mybankBillRecordModel->shopId]['merchantId'] ?? "",
                    'merchantName'         => $entryList[$mybankBillRecordModel->shopId]['merchantName'] ?? "",
                    'transType'            => $mybankBillRecordModel->transType,
                    'displayTransType'     => $mybankBillRecordModel->displayTransType,
                    'source'               => $mybankBillRecordModel->source,
                    'sourceText'           => MybankBillRecordModel::MAPPING_SOURCE[$mybankBillRecordModel->source] ?? "",
                    'transDate'            => $mybankBillRecordModel->completeTime ? date('Y-m-d H:i:s',
                        $mybankBillRecordModel->completeTime) : '',
                    'transAmount'          => bcdiv100($mybankBillRecordModel->transAmount),
                    'afterRemainingAmount' => bcdiv100($mybankBillRecordModel->afterRemainingAmount),
                    'transDesc'            => $mybankBillRecordModel->transDesc,
                    'remark'               => $mybankBillRecordModel->remark,
                    'flagDivision'         => $mybankBillRecordModel->flagDivision,
                    'billStartAt'          => $mybankBillRecordModel->billStartAt ? date('Y-m-d',
                        $mybankBillRecordModel->billStartAt) : '',
                    'billEndAt'            => $mybankBillRecordModel->billEndAt ? date('Y-m-d',
                        $mybankBillRecordModel->billEndAt) : '',
                ];
            }),
            "sourceText"    => enumToSelection(MybankBillRecordModel::MAPPING_SOURCE),
            "transTypeText" => enumToSelection(MybankBillRecordModel::MAPPING_TRANS_TYPE),
        ];
    }

    /**
     * 后台财务清分明细
     * @param $startDate
     * @param $endDate
     * @param $billStartDate
     * @param $billEndDate
     * @param $source
     * @param $merchantName
     * @param $merchantId
     * @param $shopName
     * @param $pageSize
     * @param $pageNum
     * @param $export
     * @param $billRecordId
     * @return array
     */
    public static function financeDetail(
        $startDate,
        $endDate,
        $billStartDate,
        $billEndDate,
        $source,
        $merchantName,
        $merchantId,
        $shopName,
        $pageSize,
        $pageNum,
        $export,
        $billRecordId
    ): array {
        $shopIds   = self::getShopIdsByParameter($shopName, $merchantName, $merchantId);
        $paginator = MybankBillRecordModel::query()
                                          ->with(['shopRel'])
                                          ->leftJoin('mybank_bill_record_bind', 'mybank_bill_record_bind.billRecordId',
                                              '=', 'mybank_bill_record.id')
                                          ->where('mybank_bill_record.transType',
                                              MybankBillRecordModel::WITHDRAW_TRANS_TYPE)
                                          ->when($source > 0, function ($query) use ($source) {
                                              $query->where('mybank_bill_record.source', $source);
                                          })
                                          ->when($shopIds, function ($query) use ($shopIds) {
                                              $query->whereIn('mybank_bill_record.shopId', $shopIds);
                                          })
                                          ->when($startDate && $endDate, function ($query) use ($startDate, $endDate) {
                                              $query->whereBetween('mybank_bill_record_bind.completeTime',
                                                  [strtotime($startDate), strtotime($endDate) + 86400]);
                                          })
                                          ->when($billStartDate && $billEndDate,
                                              function ($query) use ($billStartDate, $billEndDate) {
                                                  $query->where('mybank_bill_record_bind.billStartAt', '>=',
                                                      strtotime($billStartDate));
                                                  $query->where('mybank_bill_record_bind.billEndAt', '<',
                                                      strtotime($billEndDate) + 86400);
                                              })
                                          ->when($billRecordId > 0, function ($query) use ($billRecordId) {
                                              $query->where('mybank_bill_record_bind.billRecordId', $billRecordId);
                                          })
                                          ->orderBy('mybank_bill_record.transDate', 'desc')
                                          ->orderBy('mybank_bill_record.id', 'desc')
                                          ->select([
                                              'mybank_bill_record.*',
                                              'mybank_bill_record_bind.vostroBillId',
                                              'mybank_bill_record_bind.merchantId',
                                              'mybank_bill_record_bind.completeTime',
                                              'mybank_bill_record_bind.billStartAt',
                                              'mybank_bill_record_bind.billEndAt',
                                              'mybank_bill_record_bind.remark',
                                          ])
                                          ->first();
        $lists     = $total = [];
        $days      = 0;
        if ($paginator) {
            $data      = $paginator->toArray();
            $entryList = [];
            if ($data['merchantId']) {
                $entryList = MybankEntryModel::getEntryByMerchantId([$data['merchantId']]);//商户信息
                $entryList = $entryList->keyBy("merchantId")->toArray();
            }
            //查询对应订单数据
            if (in_array($data['source'], [MybankBillRecordModel::SOURCE_MEITUAN, MybankBillRecordModel::SOURCE_ELE])) {
                //外卖单
                $orderList = WaiMaiOrderModel::suffix($data['shopId'])
                                             ->where('shopId', $data['shopId'])
                                             ->where('orderStatus', WaiMaiDBEnum::ORDER_STATUS_5)
                                             ->where('sourceType',
                                                 WaiMaiDBEnum::SOURCE_TYPE_BILL_TO_TYPE[$data['source']])
                                             ->whereBetween('completeTime',
                                                 [$data['billStartAt'], $data['billEndAt'] + 86400])
                                             ->selectRaw("count(1) as total, sum(expectIncome) as totalExpectIncome, sum(brokerage) as totalBrokerage,date(FROM_UNIXTIME(completeTime)) dayTime")
                                             ->groupByRaw('date(FROM_UNIXTIME(completeTime))')
                                             ->get();
            } else {//堂食单
                $orderList = OrderSplitModel::suffix($data['shopId'])
                                            ->newQuery()
                                            ->where('shopId', $data['shopId'])
                                            ->where('orderStatus', CodeEnum::ORDER_STATUS_FINISHED)
                                            ->whereBetween('completeTime',
                                                [$data['billStartAt'], $data['billEndAt'] + 86400])
                                            ->selectRaw("count(1) as total, sum(realPayPrice) as totalExpectIncome, sum(brokerage) as totalBrokerage,date(FROM_UNIXTIME(completeTime)) dayTime")
                                            ->groupByRaw('date(FROM_UNIXTIME(completeTime))')
                                            ->get();
            }
            if ($orderList) {
                $orderList = $orderList->keyBy('dayTime')->toArray();
            }
            $days               = (int)ceil(($data['billEndAt'] - $data['billStartAt']) / 86400);
            $totalExpectIncomes = $totalBrokerages = $totalOrders = 0;
            for ($day = 0; $day <= $days; $day++) {
                $dayTime            = $data['billEndAt'] - $day * 86400;
                $orderInfo          = $orderList[date('Y-m-d', $dayTime)] ?? [];
                $totalOrder         = $orderInfo ? $orderInfo['total'] : 0; //订单数
                $totalExpectIncome  = $orderInfo ? $orderInfo['totalExpectIncome'] : 0; //订单实收
                $totalBrokerage     = $orderInfo ? $orderInfo['totalBrokerage'] : 0;//佣金费用
                $totalExpectIncomes += $totalExpectIncome;
                $totalBrokerages    += $totalBrokerage;
                $totalOrders        += $totalOrder;

                $list    = [
                    'id'                => $data['id'],
                    'shopId'            => $data['shopId'],
                    'shopCode'          => $data['shop_rel'] ? $data['shop_rel']['shopCode'] : "",
                    'shopName'          => $data['shop_rel'] ? $data['shop_rel']['name'] : "",
                    'merchantId'        => $data['merchantId'],
                    'merchantName'      => $data['merchantId'] && $entryList && $entryList[$data['merchantId']] ? $entryList[$data['merchantId']]['merchantName'] : '',
                    'transType'         => $data['transType'],
                    'displayTransType'  => $data['displayTransType'],
                    'source'            => $data['source'],
                    'sourceText'        => MybankBillRecordModel::MAPPING_SOURCE[$data['source']] ?? "",
                    'transDate'         => $data['completeTime'] ? date('Y-m-d H:i:s', $data['completeTime']) : '',
                    //完成时间
                    'transAmount'       => bcdiv100($totalExpectIncome),
                    //订单实收
                    'transDesc'         => $data['transDesc'],
                    'remark'            => $data['remark'],
                    'flagDivision'      => $data['flagDivision'],
                    'totalOrder'        => $totalOrder,
                    //订单数
                    'totalExpectIncome' => bcdiv100($totalExpectIncome - $totalBrokerage),
                    //商户收入
                    'totalBrokerage'    => bcdiv100($totalBrokerage),
                    //佣金费用
                    'billStartAt'       => $dayTime ? date('Y-m-d', $dayTime) : '',
                    'billEndAt'         => $dayTime ? date('Y-m-d', $dayTime) : '',
                    //账单周期
                ];
                $lists[] = $list;
            }

            $total = [
                'flagDivision'      => $data['flagDivision'],
                'flagDivisionText'  => $data['flagDivision'] ? MybankBillRecordModel::MAPPING_FLAG_DIVISION[$data['flagDivision']] : "",
                'transDate'         => $data['completeTime'] ? date('Y-m-d H:i:s', $data['completeTime']) : '', //完成时间
                'totalAmount'       => bcdiv100($data['transAmount']), //总金额
                'totalShopNum'      => 1, //清分门店数量
                'totalExpectIncome' => bcdiv100($totalExpectIncomes), //商户收入
                'totalBrokerage'    => bcdiv100($totalBrokerages),//佣金费用
                'totalOrders'       => $totalOrders, //订单数
            ];
        }
        return [
            'pageNum'    => $pageNum,
            'pageSize'   => $pageSize,
            'count'      => $days,
            'list'       => $lists,
            'total'      => $total,
            "sourceText" => enumToSelection(MybankBillRecordModel::MAPPING_SOURCE),
        ];
    }

    /**
     * 批次完结通知接口 - 回调
     * @param array $requestBody
     * @return array
     * @throws GuzzleException
     * @throws BaseException
     */
    public static function batchFinishNotify(array $requestBody): array
    {
        Log::info('网商银行账户对账-批次完结通知接口start：', ['requestBody' => $requestBody]);
        $batchNo = $requestBody['BatchNo'] ?? "";//批次号
        if (!$requestBody || $requestBody['Status'] != 'SUCCESS' || !$batchNo) {
            $reason = '批次返回失败';
            if ($batchNo) {
                //外卖订单和商户订单匹配记录 标记分账失败
                MybankBillRecordBindModel::query()
                                         ->where('batchNo', $batchNo)
                                         ->where('flagMark', MybankBillRecordBindModel::DEFAULT_FLAG_MARK)
                                         ->update(['flagMark' => MybankBillRecordBindModel::ERR_FLAG_MARK]);
                //批次查询接口
                $batchQuery = self::batchQuery($batchNo, $requestBody['BatchInstanceId']);
                if ($batchQuery) {
                    $reason = $batchQuery['ErrorDesc'] ?? '';
                    //返回中"存在处理失败状态批次子文件记录" --补单数据重复了，生产环境需要发邮件申请清理数据，测试环境直接换个数据重新上传
                    if ($reason && mb_strpos($reason, '存在处理失败状态批次子文件记录') !== false) {
                        $reason = '补单数据重复了';
                    }
                }
            }
            Log::info('网商银行账户对账-批次完结通知接口失败：', ['requestBody' => $requestBody]);
            $requestBodyJson = json_encode($requestBody);
            $title           = '网商银行账户对账-批次完结通知接口失败';
            $content         = <<<STR
批次号: {$batchNo}
返回信息: {$requestBodyJson}
失败原因: {$reason}

STR;
            self::sendFs($title, $content);
            return [ResponseAlias::HTTP_OK, []];
        }

        $mybankBillRecordBind = MybankBillRecordBindModel::query()
                                                         ->where('batchNo', $batchNo)
                                                         ->with('billRecordRel')
//                                                         ->where('flagMark', MybankBillRecordBindModel::MATCH_FLAG_MARK)
                                                         ->first();

        if (empty($mybankBillRecordBind)) {
            Log::info('网商银行账户对账22-批次完结通知接口未查询到批次号：', ['requestBody' => $requestBody]);
            return [ResponseAlias::HTTP_OK, []];
        }

        if ($mybankBillRecordBind->flagMark == MybankBillRecordBindModel::MATCH_FLAG_MARK) {//通过批次号查询当前记录是否修改过
            return [ResponseAlias::HTTP_OK, []];
        }
        //外卖订单和商户订单匹配记录 标记已处理
        MybankBillRecordBindModel::query()
                                 ->where('batchNo', $batchNo)
                                 ->where('flagMark', MybankBillRecordBindModel::DEFAULT_FLAG_MARK)
                                 ->update([
                                     'flagMark'     => MybankBillRecordBindModel::MATCH_FLAG_MARK,
                                     'completeTime' => time()
                                 ]);

        $list          = MybankBillRecordBindModel::query()
                                                  ->where('batchNo', $batchNo)
                                                  ->select(['billRecordId', 'vostroBillId'])
                                                  ->get();
        $billRecordIds = $list->pluck('billRecordId')->toArray();
        if (!$billRecordIds) {
            Log::info('网商银行账户对账-批次完结通知接口未查询到批次号：', ['requestBody' => $requestBody]);
            return [ResponseAlias::HTTP_OK, []];
        }
        //账单记录管理 标记已处理
        MybankBillRecordModel::query()
                             ->whereIn('id', $billRecordIds)
                             ->where('flagDivision', MybankBillRecordModel::DEFAULT_FLAG_DIVISION)
                             ->update(['flagDivision' => MybankBillRecordModel::MATCH_FLAG_DIVISION]);
        //对账文件批次号信息记录 标记已处理
        MybankBatchNoRecordModel::query()
                                ->where('batchNo', $batchNo)
                                ->where('flagMark', MybankBatchNoRecordModel::DEFAULT_FLAG_MARK)
                                ->update(['flagMark' => MybankBatchNoRecordModel::MATCH_FLAG_MARK]);

        // 获取账单周期
        $billDateTimes = MybankOrderWithholdService::calcWaimaiDateTimeInterval(
            $mybankBillRecordBind->billRecordRel->shopId,
            $mybankBillRecordBind->billRecordRel->id,
            $mybankBillRecordBind->billRecordRel->source
        );

        if (!empty($billDateTimes)) {
            // 更新账单周期
            MybankBillRecordBindModel::query()
                                     ->where('batchNo', $batchNo)
                                     ->where('flagMark', MybankBillRecordBindModel::MATCH_FLAG_MARK)
                                     ->update([
                                         'billStartAt' => $billDateTimes['startAt'],
                                         'billEndAt'   => $billDateTimes['endAt']
                                     ]);
        }

        Log::info('网商银行账户对账-批次完结通知接口end：', ['requestBody' => $requestBody, 'ids' => $billRecordIds]);
        $title   = '网商银行账户对账-批次完结通知完成';
        $content = <<<STR
批次号: {$batchNo}

STR;
        self::sendFs($title, $content);
        //继续处理下一个店铺账单数据

        self::createBatchMatchBillRecord();
        self::afterSuccessBatchNotify($batchNo);

        self::sendFs('完成处理通知', '完成处理通知' . $batchNo);
        return [ResponseAlias::HTTP_OK, []];
    }

    public static function afterSuccessBatchNotify(string $batchNo)
    {
        // 不影响主流程
        try {
            dispatch(function () use ($batchNo) {
                // 走协议代扣
                (new MybankOrderWithholdV2Service())->withholdFzApply($batchNo);
            })->onQueue('{QUEUE-RMS-API-MYBANK-DEFAULT}');

        } catch (\Exception $exception) {
            Log::channel('mybank')->error('afterSuccessBatchNotify_error', [
                'msg'  => $exception->getMessage(),
                'code' => $exception->getCode(),
                'line' => $exception->getLine(),
                'file' => $exception->getFile(),
            ]);
            return;
        }
    }

    /**
     * 渠道结算入账通知接口 - 回调
     * @param array $requestBody
     * @return array
     */
    public static function channelVostroNotify(array $requestBody): array
    {
        Artisan::call('mybank:query-account-balance');
        Log::info('网商银行账户对账-渠道结算入账通知接口start：', ['requestBody' => $requestBody]);
        if (!$requestBody) {
            Log::info('网商银行账户对账-渠道结算入账通知接口失败：', ['requestBody' => $requestBody]);
            return [ResponseAlias::HTTP_OK, []];
        }
        $mybankVostroBillModel = MybankVostroBillModel::query()
                                                      ->where('orderNo', $requestBody['OrderNo'])
                                                      ->first();
        if ($mybankVostroBillModel) {//通过订单号查询当前记录是否新增过
            return [ResponseAlias::HTTP_OK, []];
        }

        $data = [
            'isvOrgId'      => $requestBody['IsvOrgId'],           //合作方机构号（网商银行分配）
            'merchantId'    => $requestBody['MerchantId'] ?? "",   //商户号
            'outTradeNo'    => $requestBody['OutTradeNo'],         //原外部订单请求流水号
            'orderNo'       => $requestBody['OrderNo'],            //原网商订单号
            'transNo'       => $requestBody['TransNo'],            //入账流水号
            'channelId'     => $requestBody['ChannelId'],          //出款渠道id（9001大额、9002小额、9003超网、9100支付宝）
            'payerBankId'   => $requestBody['PayerBankId'],        //付款方银行编码
            'payerCardNo'   => $requestBody['PayerCardNo'],        //付款方卡号
            'payerCardName' => $requestBody['PayerCardName'],      //付款方卡号户名
            'payeeCardNo'   => $requestBody['PayeeCardNo'],        //收款方卡号
            'payeeCardName' => $requestBody['PayeeCardName'],      //收款方户名
            'vostroScene'   => $requestBody['VostroScene'],        //来账场景
            'amount'        => $requestBody['Amount'],             //订单金额(金额为分)
            'transferDate'  => strtotime($requestBody['TransferDate']),       //转账时间
            'currency'      => $requestBody['Currency'],           //币种，默认CNY
            'memo'          => $requestBody['Memo'] ?? "",         //备注
            'extInfo'       => $requestBody['ExtInfo'] ?? "",      //扩展信息
            'status'        => $requestBody['Status'],             //状态
            'remark'        => $requestBody['Remark'] ?? '',       //转账附言
        ];

        $res     = MybankVostroBillModel::addData($data);
        $id      = $res ? $res->id : 0;
        $amount  = $requestBody['Amount'] ?? 0;
        $amount  = bcdiv100($amount);
        $date    = date('Y-m-d H:i:s', strtotime($requestBody['TransferDate']));
        $content = <<<STR
        金额: {$amount}
        来账场景: {$data['vostroScene']}
        转账时间: {$date}
        转账附言: {$data['remark']}
        状态: {$requestBody['Status']}

        STR;
        if (!$id) {
            $title = '网商银行账户对账-渠道结算入账通知接口数据插入失败';
            self::sendFs($title, $content);
            Log::info('网商银行账户对账-渠道结算入账通知接口数据插入失败：', ['requestBody' => $requestBody]);
            return [ResponseAlias::HTTP_OK, []];
        }
        $title = '网商银行账户对账-渠道结算入账通知接口成功';
        self::sendFs($title, $content);
        Log::info('网商银行账户对账-渠道结算入账通知接口end：', ['requestBody' => $requestBody, 'id' => $id]);

        return [ResponseAlias::HTTP_OK, []];
    }

    /**
     * 批次查询接口
     * @param $batchNo
     * @param $batchInstanceId
     * @return array
     * @throws GuzzleException
     * @throws BaseException
     */
    public static function batchQuery($batchNo, $batchInstanceId): array
    {
        $resultJson = MybankCreateBatchRemote::batchQuery($batchInstanceId, $batchNo);
        return $resultJson['response']['body'] ?? [];
    }

    /**
     * 网商银行账户对账处理
     * 查询饿了么和美团平台订单数据进行匹配账单-匹配我们数据库内平台订单和网商银行返回账单明细对比
     * @throws GuzzleException|BaseException
     */
    public static function createBatchMatchBillRecord()
    {
        $time = time();
        //网商银行打款周期-三天 查询外卖平台提现订单时间为3天前
        /*$startTime = strtotime(date('Y-m-d', strtotime('-3 day')));//每天早上处理查询三天前的账单
        if (config('app.env') == 'dev' || config('app.env') == 'test' || config('app.env') == 'qa') {
            $startTime = $time;
        }*/
        $startTime        = $time;
        $eleCacheMark     = 0;//self::platformCacheMark(MybankBillRecordModel::SOURCE_ELE, 1);
        $meituanCacheMark = 0;//self::platformCacheMark(MybankBillRecordModel::SOURCE_MEITUAN, 1);
        $canteenCacheMark = 0;//self::platformCacheMark(MybankBillRecordModel::SOURCE_CANTEEN, 1);
        $date             = date('Ymd');
//        $date        = '20230904';
//        $startTime   = '1693800011';
        $dateTime    = date('Y-m-d H:i:s');
        $totalAmount = MybankVostroBillModel::totalAmount();

        $totalAmount = bcdiv100($totalAmount);

        Log::channel('mybank')->notice('网商银行账户对账-未分配账单金额：', [
            'totalAmount' => $totalAmount,
        ]);

        // 查询有没有未处理完成的批次--上一个批次完成后再创建新的批次
        $batchNoCount = MybankBatchNoRecordModel::getCount(MybankBatchNoRecordModel::DEFAULT_FLAG_MARK);
        if ($batchNoCount > 0) {
            Log::channel('mybank')->notice('网商银行账户对账-有未处理完成的批次：', [
                'batchNoCount' => $batchNoCount,
                'msg'          => '上一个批次完成后再创建新的批次',
            ]);
            return;
        }
        if ($totalAmount) {
            //饿了么外卖账单数据
            if (!$eleCacheMark) {
//                $res = self::checkBillRecord($startTime, $date, $time, MybankBillRecordModel::SOURCE_ELE);
                $res = self::matchBillRecordByDate($date, $time, MybankBillRecordModel::SOURCE_ELE);
                if ($res['code'] == 200) {//批次创建完成 等待回调
                    return;
                }
            }

            //美团外卖账单数据
            if (!$meituanCacheMark) {
                $res = self::checkBillRecord($startTime, $date, $time, MybankBillRecordModel::SOURCE_MEITUAN);
                if ($res['code'] == 200) {//批次创建完成 等待回调
                    return;
                }
            }

            //堂食账单数据
            if (!$canteenCacheMark) {
                //查询堂食提现订单时间为1天前
                $startTime = strtotime(date('Y-m-d', strtotime('-1 day')));//每天早上处理查询1天前的账单
                if (config('app.env') == 'dev' || config('app.env') == 'test' || config('app.env') == 'qa') {
                    $startTime = $time;
                }
                $res = self::matchBillRecordByDate($date, $time, MybankBillRecordModel::SOURCE_CANTEEN);
                if ($res['code'] == 200) {//批次创建完成 等待回调
                    return;
                }
            }
        }
    }

    /**
     * 三方账单数据比对-外卖,堂食
     * @param $startTime
     * @param $date
     * @param $time
     * @param $source
     * @return array
     * @throws BaseException
     * @throws GuzzleException
     */
    public static function checkBillRecord($startTime, $date, $time, $source): array
    {
        // TODO 可以单独拎出来这个方法, 走特殊处理流程处理.
        $data       = ['code' => 500, 'msg' => '账单匹配未完成'];
        $sourceText = MybankBillRecordModel::MAPPING_SOURCE[$source] ?? "";
        $shopIds    = MybankBillRecordModel::getBillRecordGroupShopIds(MybankBillRecordModel::WITHDRAW_TRANS_TYPE,
            MybankBillRecordModel::DEFAULT_FLAG_MARK, $startTime, $source);

        if (!$shopIds) {
            Log::channel('mybank')->info($sourceText . '分账数据-平台记录数据不存在', [
                'shopIds' => $shopIds,
            ]);
            return ['code' => 500, 'msg' => '数据不存在'];
        }
//        $shopIds = [
//            [
//                'shopId' => 15019
//            ]
//        ];

        foreach ($shopIds as $v) {
            $getMerchantInfo = self::getMerchantIdByShopId($v['shopId']);
            if ($getMerchantInfo && $getMerchantInfo['merchantId']) {
                //单个店铺账单匹配
                $res = self::oneShopMatchBill($v['shopId'], $startTime, $getMerchantInfo, $source);

                if ($res) {
                    //匹配成功 创建结算批次
                    $res2 = self::batchCreate($res, $v['shopId'], $date, $time, $getMerchantInfo, $source);
                    if ($res2 && $res2['code'] == '200') {//创建成功
                        $data = ['code' => 200, 'msg' => '创建成功'];
                        break;//目前批次是串行处理的，需要等上一个批次结算完成后再创建下一个批次，如果上一个失败的话后面的批次就不会处理了--这里改成单个店铺处理然后在批次回调再请求
                    }
                }
            }
        }

        return $data;
    }

    /**
     * 通过店铺id查询商户信息
     * @param int $shopId
     * @return array
     */
    public static function getMerchantIdByShopId(int $shopId): array
    {
        $merchantId = $merchantName = '';
        $entryId    = MybankShopBindModel::getEntryIdByShopId($shopId);
        if ($entryId) {
            $entryInfo    = MybankEntryModel::getEntryInfo($entryId);//商户信息
            $merchantId   = $entryInfo ? $entryInfo->merchantId : '';
            $merchantName = $entryInfo ? $entryInfo->merchantName : '';
        }
        if (!$merchantId) {
            Log::channel('mybank')->info('网商银行账户对账-未找到商户信息', [
                'shopId'     => $shopId,
                'entryId'    => $entryId,
                'merchantId' => $merchantId,
            ]);
        }
        return [
            'shopId'       => $shopId,
            'entryId'      => $entryId,
            'merchantId'   => $merchantId,
            'merchantName' => $merchantName
        ];
    }

    /**
     * 数量自增
     * @param $identification
     * @return mixed
     */
    public static function autoincrementByRedis($identification)
    {
        $key = sprintf('mybank:' . '%s:%s', date('Ymd'), $identification);

        $res = Redis::incr($key, 1);
        if ($res == 1) {
            Redis::expireAt($key, strtotime(date('Y-m-d')) + 86401);
        }
        return $res;
    }

    /**
     * 单个门店匹配账单与网商账单对比
     * @param int $shopId
     * @param string $startTime
     * @param array $getMerchantInfo
     * @param int $source
     * @return array[]
     */
    public static function oneShopMatchBill(
        int $shopId,
        string $startTime,
        array $getMerchantInfo,
        int $source
    ): array {
        $sourceText = MybankBillRecordModel::MAPPING_SOURCE[$source] ?? "";
        $data       = $relationData = [];
        //查询单个门店3天前的-美团，饿了么账单明细，堂食账单明细
        $billRecordList = $billRecordListTemp = MybankBillRecordModel::getBillRecordList($shopId,
            MybankBillRecordModel::WITHDRAW_TRANS_TYPE, MybankBillRecordModel::DEFAULT_FLAG_MARK, $startTime, $source);
        if (!$billRecordList) {//外卖平台记录数据都不存在时
            Log::channel('mybank')->notice($sourceText . '分账数据-平台记录数据不存在', [
                'shopId'    => $shopId,
                'startTime' => $startTime,
            ]);
            return [];
        }

        MybankVostroBillModel::query()
                             ->where('type', 0)
                             ->where('flagMark', MybankVostroBillModel::DEFAULT_FLAG_MARK)
                             ->orderBy('id')
                             ->chunk(500, function ($billList) use (
                                 &$billRecordListTemp,
                                 &$data,
                                 &$relationData
                             ) {
                                 foreach ($billList as $v) {
                                     foreach ($billRecordListTemp as $k => $ele) {
                                         if ($ele['transAmount'] && $ele['transAmount'] == $v['amount']) {//匹配外卖平台提现记录对应网商银行到账记录
                                             $data[]         = $ele;
                                             $relationData[] = [
                                                 'vostroBillId' => $v['id'],
                                                 'billRecordId' => $ele['id'],
                                             ];
                                             unset($billRecordListTemp[$k]);
                                             break;
                                         }

                                     }
                                 }
                             });

//        dd($billRecordListTemp);

        if (count($billRecordListTemp) > 0) {//单个门店账单记录未匹配完，说明还有未结清的账单，这里做异常处理通知

            $totalTransAmount = array_sum(array_column($billRecordListTemp, 'transAmount'));
            $totalTransAmount = bcdiv100($totalTransAmount);
            $total            = count($billRecordListTemp);
            Log::channel('mybank')->notice($sourceText . '分账数据-平台记录未匹配完', [
                'shopId'           => $shopId,
                'startTime'        => $startTime,
                'totalTransAmount' => $totalTransAmount,
                'total'            => $total,
            ]);

            return [];
        }
        $totalAmount = array_sum(array_column($billRecordList, 'transAmount'));
        $totalAmount = bcdiv100($totalAmount);

        Log::channel('mybank')->notice($sourceText . '分账数据-记录匹配完成', [
            'shopId'      => $shopId,
            'startTime'   => $startTime,
            'totalAmount' => $totalAmount,
        ]);
        return [
            'data'         => $data,
            'relationData' => $relationData,
            'totalAmount'  => $totalAmount,
        ];
    }

    /**
     * 批次创建
     * @param array $shopMatchBillData
     * @param int $shopId
     * @param string $date
     * @param int $time
     * @param array $getMerchantInfo
     * @param int $source
     * @return array
     * @throws BaseException
     * @throws GuzzleException
     */
    public static function batchCreate(
        array $shopMatchBillData,
        int $shopId,
        string $date,
        int $time,
        array $getMerchantInfo,
        int $source
    ): array {
        $sourceText          = MybankBillRecordModel::MAPPING_SOURCE[$source] ?? "";
        $body                = [];
        $acquireId           = 'DEFAULT';//门店自主收银模式下，填写对应的渠道编号，对接时找技术同学确认；
        $batchDate           = $date;    //对账日
        $fuyouBillRecordDate = [];
        //查询堂食订单
        if ($source == MybankBillRecordModel::SOURCE_CANTEEN) {
            $transDates = array_unique(array_column($shopMatchBillData['data'], 'transDate'));
            if ($transDates) {
                foreach ($transDates as &$v) {
                    $v = date('Ymd', $v);
                }
                $fuyouBillRecordDate = MybankFuyouBillRecordModel::query()
                                                                 ->where('shopId', $shopId)
                                                                 ->where('mybankMerchantId',
                                                                     $getMerchantInfo['merchantId'])
                                                                 ->whereIn('transactionDate', $transDates)
                                                                 ->where('mybankOrderNo', '!=', 0)
                                                                 ->where('transactionAmount', '>', 0)
                                                                 ->get()
                                                                 ->toArray();
                if (!$fuyouBillRecordDate) {
                    Log::channel('mybank')->notice($sourceText . '分账数据-查询堂食订单失败', [
                        'shopMatchBillData' => $shopMatchBillData,
                        'shopId'            => $shopId,
                        'getMerchantInfo'   => $getMerchantInfo,
                        'transDates'        => $transDates
                    ]);

                    return [
                        'msg'  => '网商银行账户对账-查询堂食订单失败',
                        'data' => ['shopMatchBillData' => $shopMatchBillData, 'shopId' => $shopId],
                        'code' => 400,
                    ];
                }
                //查询退款订单
                $fuyouBillRecordDataRefund = MybankFuyouBillRecordModel::query()
                                                                       ->where('shopId', $shopId)
                                                                       ->where('mybankMerchantId',
                                                                           $getMerchantInfo['merchantId'])
                                                                       ->whereIn('transactionDate', $transDates)
                                                                       ->where('transactionAmount', '<', 0)
                                                                       ->get();

                if ($fuyouBillRecordDataRefund) {
                    $fuyouBillRecordDataRefund = $fuyouBillRecordDataRefund->keyBy('originalTransactionOrderNo')
                                                                           ->toArray();
                    foreach ($fuyouBillRecordDate as $k => &$v) {
                        $fuyouBillRecordRefundData = $fuyouBillRecordDataRefund[$v['merchantOrderNo']] ?? [];//通过退款 原交易订单号 匹配 商户订单号
                        if ($fuyouBillRecordRefundData) {
                            if (($v['transactionAmount'] + $fuyouBillRecordRefundData['transactionAmount']) <= 0) {//判断是否全部退款
                                unset($fuyouBillRecordDate[$k]);
                            } else {
                                $v['transactionAmount'] = $v['transactionAmount'] + $fuyouBillRecordRefundData['transactionAmount'];
                                $v['transactionFee']    = ($v['transactionFee'] + $fuyouBillRecordRefundData['transactionFee']) <= 0 ? $v['transactionFee'] + $fuyouBillRecordRefundData['transactionFee'] : 0;
                            }
                        }
                    }
                    if (count($fuyouBillRecordDate) == 0) {
                        Log::channel('mybank')->notice($sourceText . '分账数据-堂食订单已全部退款', [
                            'fuyouBillRecordDataRefund' => $fuyouBillRecordDataRefund,
                            'shopMatchBillData'         => $shopMatchBillData,
                            'shopId'                    => $shopId,
                            'getMerchantInfo'           => $getMerchantInfo,
                            'transDates'                => $transDates
                        ]);

                        return [
                            'msg'  => '网商银行账户对账-堂食订单已全部退款',
                            'data' => [
                                'fuyouBillRecordDataRefund' => $fuyouBillRecordDataRefund,
                                'shopMatchBillData'         => $shopMatchBillData,
                                'shopId'                    => $shopId
                            ],
                            'code' => 400,
                        ];
                    }
                }
            }
        }
        //批次号 - 以今天的时间为准
        $batchDateNow = date('Ymd');
        $batchNo      = $batchDateNow . "_" . str_pad(self::autoincrementByRedis('batchNo'), 2, "0", STR_PAD_LEFT);

        //3.文件上传
        MybankCreateBatchRemote::batchFileUpload($acquireId, $batchNo, $batchDate, $getMerchantInfo['merchantId'],
            $shopMatchBillData['data'], $source, $fuyouBillRecordDate);

        //4.创建结算批次
        $resultJson = MybankCreateBatchRemote::batchCreate($batchNo, $source);
        $body       = $resultJson["response"]["body"];
        if ($body['RespInfo']['ResultCode'] != '0000') {
            Log::channel('mybank')->error($sourceText . '分账数据-创建结算批次失败', [
                'resBody'         => $body,
                'batchNo'         => $batchNo,
                'shopId'          => $shopId,
                'getMerchantInfo' => $getMerchantInfo,
                'fsNotifyUids'    => [
                    '346gc6ea'
                ]
            ]);

            return [
                'msg'  => '网商银行账户对账-' . $sourceText . '创建结算批次失败',
                'data' => ['resBody' => $body, 'batchNo' => $batchNo],
                'code' => 400,
            ];
        }
        $batchInstanceId = $body['BatchInstanceId'] ?? '';//批次实例号，由本次批次处理的id号
        $acquireId       = $body['AcquireId'] ?? '';//渠道编号

        DB::beginTransaction();
        try {
            //绑定网商银行账单记录和外卖平台提现记录
            collect($shopMatchBillData['relationData'])->chunk(500)->each(function ($item) use (
                $batchNo,
                $getMerchantInfo,
                $batchInstanceId,
                $acquireId,
                $time
            ) {
                $createData = $item->map(function ($data) use (
                    $batchNo,
                    $time,
                    $getMerchantInfo,
                    $acquireId,
                    $batchInstanceId
                ) {
                    return [
                        'billRecordId'    => $data['billRecordId'],//外卖平台账单记录 ID
                        'vostroBillId'    => $data['vostroBillId'],//网商银行来账记录 ID
                        'batchNo'         => $batchNo,//批次号
                        'batchInstanceId' => $batchInstanceId,//批次实例号，由本次批次处理的id号
                        'acquireId'       => $acquireId,//渠道编号
                        'merchantId'      => $getMerchantInfo['merchantId'],//网商的商户号
                        'createdAt'       => $time,
                    ];
                })->toArray();
                MybankBillRecordBindModel::query()->insert($createData);//网商银行来账记录与外卖平台账单记录关联绑定
                $vostroBillIds = $item->pluck('vostroBillId')->toArray();
                $billRecordIds = $item->pluck('billRecordId')->toArray();
                if ($vostroBillIds) {//网商银行账户明细
                    MybankVostroBillModel::query()
                                         ->whereIn('id', $vostroBillIds)
                                         ->where('flagMark', MybankVostroBillModel::DEFAULT_FLAG_MARK)
                                         ->update(['flagMark' => MybankVostroBillModel::MATCH_FLAG_MARK]);
                }
                if ($billRecordIds) {//账单记录管理
                    MybankBillRecordModel::query()
                                         ->whereIn('id', $billRecordIds)
                                         ->where('flagMark', MybankBillRecordModel::DEFAULT_FLAG_MARK)
                                         ->update(['flagMark' => MybankBillRecordModel::MATCH_FLAG_MARK]);
                }
            });
            DB::commit();
        } catch (\Exception $e) {
            DB::rollBack();
            Log::channel('mybank')->error($sourceText . '分账数据-批次创建sql失败', [
                'shopId'          => $shopId,
                'msg'             => $e->getMessage(),
                'batchNo'         => $batchNo,
                'getMerchantInfo' => $getMerchantInfo,
                'fsNotifyUids'    => [
                    '346gc6ea'
                ]
            ]);

            return [
                'msg'  => $e->getMessage(),
                'code' => 500,
            ];
        }
        Log::channel('mybank')->notice($sourceText . '分账数据-批次创建成功', [
            'body'            => $body,
            'shopId'          => $shopId,
            'batchNo'         => $batchNo,//批次号
            'batchInstanceId' => $batchInstanceId,//批次实例号
            'acquireId'       => $acquireId,//渠道编号
            'merchantId'      => $getMerchantInfo['merchantId'],//商户号
            'totalAmount'     => $shopMatchBillData['totalAmount'],//匹配金额
        ]);

        return [
            'data' => [
                'merchantId' => $getMerchantInfo['merchantId'],
                'batchNo'    => $batchNo,
                'body'       => $body,
            ],
            'msg'  => '成功',
            'code' => 200,
        ];
    }

    /**
     * 发送飞书群消息
     * @param string $title
     * @param string $content
     */
    public static function sendFs(string $title, string $content)
    {
        SendFs::newRobot(SendFs::ROBOT_BATCH_BILL_MATCH)
              ->setTitleContent($title, $content)
              ->send();
    }

    /**
     * 获取商户余额
     *
     * @param $merchantId
     * @return mixed
     * @throws GuzzleException
     */
    public static function getMerchantBalance($merchantId): array
    {
        $balanceInfo = [
            'BALANCE_FREEZE' => '0',
            'PAY'            => '0',
        ];
        try {
            // 获取余额
            $resultJson  = MybankAccountRemote::merchantBalanceQuery($merchantId);
            $balanceInfo = $resultJson["response"]["body"]['BalanceInfo'];
            $balanceInfo = json_decode(base64_decode($balanceInfo), true);

            if (empty($balanceInfo['BALANCE_FREEZE'])) {
                $balanceInfo['BALANCE_FREEZE'] = '0';
            }

            return $balanceInfo;
        } catch (\Exception $exception) {
            Log::info('获取余额异常：', ['res' => $exception->getMessage()]);
//            throw new BalanceException(0, '获取余额异常');
            return $balanceInfo;
        }
    }

    /**
     * 平台余额管理
     *
     * @return int[]
     * @throws GuzzleException
     */
    public static function getAccountBalance()
    {
        $balanceInfo = [
            'balance' => 0
        ];
        try {
            // 获取余额
            $resultJson             = MybankAccountRemote::accountBalanceQuery();
            $balanceInfo['balance'] = $resultJson["response"]["body"]['Amount'];
            return $balanceInfo;
        } catch (\Exception $exception) {
            Log::info('获取余额异常：', ['res' => $exception->getMessage()]);
            return $balanceInfo;
        }
    }

    /**
     * 平台资金明细
     *
     * @return mixed
     * @throws BaseException
     * @throws GuzzleException
     */
    public static function getAccountVostroBatchQuery(): array
    {
        $result   = MybankAccountRemote::accountVostroBatchQuery();
        $listStr  = $result['response']['body']['VostroInfoList'];
        $listJson = base64_decode($listStr);
        $list     = json_decode($listJson, true);
        return $list;
    }

    /**
     * 来帐汇入通知接口
     * @param array $requestBody
     * @return array
     * @throws GuzzleException
     */
    public static function vostroNotify(array $requestBody): array
    {
        // TODO 临时校验
//        return [ResponseAlias::HTTP_OK, []];

        Log::channel('mybank')->info('网商银行账户-来帐汇入通知接口start：', ['requestBody' => $requestBody]);
        if (!$requestBody) {
            Log::channel('mybank')->info('网商银行账户-来帐汇入通知接口失败：', ['requestBody' => $requestBody]);
            return [ResponseAlias::HTTP_OK, []];
        }

        // 查询当前余额
        Artisan::call('mybank:query-account-balance');
        $mybankVostroBillModel = MybankVostroBillModel::query()
                                                      ->where('orderNo', $requestBody['OrderNo'])
                                                      ->first();
        if ($mybankVostroBillModel) {//通过订单号查询当前记录是否新增过
            return [ResponseAlias::HTTP_OK, []];
        }
        $transferDate = strtotime($requestBody['TransferDate']);
        $data         = [
            'isvOrgId'      => $requestBody['IsvOrgId'] ?: '',
            //合作方机构号（网商银行分配）
            'merchantId'    => $requestBody['MerchantId'] ?? '',
            //商户号
            'outTradeNo'    => $requestBody['OutTradeNo'] ?: '',
            //原外部订单请求流水号
            'orderNo'       => $requestBody['OrderNo'] ?: '',
            //原网商订单号
            'transNo'       => $requestBody['TransNo'] ?: '',
            //入账流水号
            'channelId'     => $requestBody['ChannelId'] ?: '',
            //出款渠道id（9001大额、9002小额、9003超网、9100支付宝）
            'payerBankId'   => $requestBody['PayerBankOrgId'] ?: '',
            //付款方银行联行号
            'payerCardNo'   => $requestBody['PayerCardNo'] ?: '',
            //付款方卡号
            'payerCardName' => $requestBody['PayerCardName'] ?: '',
            //付款方卡号户名
            'payeeCardNo'   => $requestBody['PayeeCardNo'] ?: '',
            //收款方卡号
            'payeeCardName' => $requestBody['PayeeCardName'] ?: '',
            //收款方户名
            'amount'        => $requestBody['TotalAmount'] ?: '',
            //订单金额(金额为分)
            'transferDate'  => $transferDate ?: 0,
            //转账时间
            'currency'      => $requestBody['Currency'] ?: '',
            //币种，默认CNY
            'memo'          => $requestBody['Memo'] && !empty($requestBody['Memo']) ?? "",
            //备注
            'extInfo'       => $requestBody['ExtInfo'] && !empty($requestBody['ExtInfo']) ? base64_decode($requestBody['ExtInfo']) : "",
            //扩展信息
            'status'        => $requestBody['Status'] ?: '',
            //状态
            'remark'        => $requestBody['Remark'] ?: '',
            //转账附言
            'vostroType'    => $requestBody['VostroType'] ?? "",
            //来账类型 ORDER_VOSTRO：订单码支付ACCOUNT_VOSTRO：外标户支付
            'vostroScene'   => $requestBody['VostroScene'] ?? "",
            //来账场景 PRE_CHARGE： 预充PRE_PAY：预付
            'type'          => MybankVostroBillModel::RECHARGE_TYPE,
            //充值
        ];
        $res          = MybankVostroBillModel::addData($data);
        $id           = $res ? $res->id : 0;
        $amount       = $data['amount'];
        $amount       = bcdiv100($amount);
        $date         = date('Y-m-d H:i:s', $transferDate);
        $content      = <<<STR
        金额: {$amount}
        来账场景: {$data['vostroScene']}
        转账时间: {$date}
        转账附言: {$data['remark']}
        状态: {$data['status']}

        STR;
        if (!$id) {
            $title = '网商银行账户-来帐汇入通知接口数据插入失败';
            self::sendFs($title, $content);
            Log::info('网商银行账户-来帐汇入通知接口数据插入失败：', ['requestBody' => $requestBody]);
            return [ResponseAlias::HTTP_OK, []];
        }
        // 获取余额
        $balanceInfo   = self::getMerchantBalance($data['merchantId']);
        $balanceFreeze = $balanceInfo['BALANCE_FREEZE'] ?? 0;
        $balancePAY    = $balanceInfo['PAY'] ?? 0;

        // 钱包添加记录
        MybankOrderWithholdService::walletRecordAdd(
            $data['merchantId'],
            MybankWalletRecordModel::RECHARGE_TRANS_TYPE,
            $data['amount'],
            (int)bcadd($balanceFreeze, $balancePAY),
            0,
            $id,
            MybankWalletRecordModel::RECORD_ID_TYPE_VOSTRO_BILL,
            MybankWalletRecordModel::PLATFORM_TYPE_MYBANK,
            "商户充值", $data['orderNo'], $data['remark'], $transferDate,
            MybankWalletRecordModel::SUCCESS_STATUS,
            MybankWalletRecordModel::SHOW_RECORD
        );

        $title = '网商银行账户-来帐汇入通知接口成功';
//        self::sendFs($title, $content);
        Log::info('网商银行账户-来帐汇入通知接口end：', ['requestBody' => $requestBody, 'id' => $id]);
        return [ResponseAlias::HTTP_OK, []];
    }

    /**
     * 提现结果通知接口
     * @param array $requestBody
     * @return array
     * @throws GuzzleException
     */
    public static function withdrawNotify(array $requestBody): array
    {
        Log::info('网商银行账户-提现结果通知接口start：', ['requestBody' => $requestBody]);
        if (!$requestBody) {
            Log::info('网商银行账户-提现结果通知接口失败：', ['requestBody' => $requestBody]);
            return [ResponseAlias::HTTP_OK, []];
        }
        $mybankVostroBillModel = MybankVostroBillModel::query()
                                                      ->where('orderNo', $requestBody['OrderNo'])
                                                      ->first();
        if ($mybankVostroBillModel) {//通过订单号查询当前记录是否新增过
            return [ResponseAlias::HTTP_OK, []];
        }
        $transferDate       = strtotime($requestBody['WithdrawFinishDate']);
        $data               = [
            'isvOrgId'          => $requestBody['IsvOrgId'], //合作方机构号（网商银行分配）
            'merchantId'        => $requestBody['MerchantId'] ?? "", //商户号
            'outTradeNo'        => $requestBody['OutTradeNo'], //原外部订单请求流水号
            'orderNo'           => $requestBody['OrderNo'], //原网商订单号
            'transNo'           => $requestBody['TransNo'] ?? "", //入账流水号
            'channelId'         => $requestBody['ChannelId'] ?? "", //出款渠道id（9001大额、9002小额、9003超网、9100支付宝）
            'payerBankId'       => $requestBody['PayerBankId'] ?? "", //付款方银行编码
            'payerCardNo'       => $requestBody['PayerCardNo'] ?? "", //付款方卡号
            'payerCardName'     => $requestBody['PayerCardName'] ?? "", //付款方卡号户名
            'payeeCardNo'       => $requestBody['BankCardNo'], //绑定银行卡号
            'payeeCardName'     => $requestBody['BankCertName'], //绑定卡号户名
            'vostroScene'       => $requestBody['VostroScene'] ?? "", //来账场景
            'amount'            => $requestBody['TotalAmount'] - $requestBody['PlatformFee'], //订单金额(金额为分)
            'withdrawApplyDate' => strtotime($requestBody['WithdrawApplyDate']), //提现时间
            'transferDate'      => $transferDate, //提现完成时间
            'currency'          => $requestBody['Currency'], //币种，默认CNY
            'platformFee'       => $requestBody['PlatformFee'], //平台设置提现手续用（银行控制盖帽比率），用户实收资金= TotalAmount - PlatformFee
            'FeeCurrency'       => $requestBody['FeeCurrency'], //币种，默认CNY
            'memo'              => $requestBody['Scene'] ?? "", //备注
            'extInfo'           => $requestBody['ErrorDesc'] ?? "", //扩展信息
            'status'            => $requestBody['Status'], //状态
            'remark'            => $requestBody['Remark'] ?? "",//转账附言
            'type'              => MybankVostroBillModel::WITHDRAW_TYPE, //提现
        ];
        $res                = MybankVostroBillModel::addData($data);
        $id                 = $res ? $res->id : 0;
        $amount             = $requestBody['TotalAmount'] - $requestBody['PlatformFee'] ?? 0;
        $amount             = bcdiv100($amount);
        $withdrawApplyDate  = date('Y-m-d H:i:s', strtotime($requestBody['WithdrawApplyDate']));
        $withdrawFinishDate = date('Y-m-d H:i:s', $transferDate);
        $content            = <<<STR
        金额: {$amount}
        提现申请时间: {$withdrawApplyDate}
        提现完成时间: {$withdrawFinishDate}
        状态: {$requestBody['Status']}

        STR;
        if (!$id) {
            $title = '网商银行账户-提现结果通知接口数据插入失败';
            self::sendFs($title, $content);
            Log::info('网商银行账户-提现结果通知接口数据插入失败：', ['requestBody' => $requestBody]);
            return [ResponseAlias::HTTP_OK, []];
        }

        // 获取余额
        $balanceInfo   = self::getMerchantBalance($data['merchantId']);
        $balanceFreeze = $balanceInfo['BALANCE_FREEZE'] ?? 0;
        $balancePAY    = $balanceInfo['PAY'] ?? 0;

        // 钱包添加记录
        MybankOrderWithholdService::walletRecordAdd(
            $requestBody['MerchantId'],
            MybankWalletRecordModel::INCOME_TRANS_TYPE,
            $data['amount'],
            (int)bcadd($balanceFreeze, $balancePAY),
            0,
            $id,
            MybankWalletRecordModel::RECORD_ID_TYPE_VOSTRO_BILL,
            MybankWalletRecordModel::PLATFORM_TYPE_MYBANK,
            "商户提现", $requestBody['OrderNo'], '', $transferDate,
            MybankWalletRecordModel::SUCCESS_STATUS,
            MybankWalletRecordModel::SHOW_RECORD
        );

        $title = '网商银行账户-提现结果通知接口成功';
        self::sendFs($title, $content);
        Log::info('网商银行账户-提现结果通知接口end：', ['requestBody' => $requestBody, 'id' => $id]);
        return [ResponseAlias::HTTP_OK, []];

    }

    /**
     * 充值退款结果通知接口
     * @param array $requestBody
     * @return array
     * @throws GuzzleException
     */
    public static function refundNotify(array $requestBody): array
    {
        Log::info('网商银行账户-充值退款结果通知接口start：', ['requestBody' => $requestBody]);
        if (!$requestBody) {
            return [ResponseAlias::HTTP_OK, []];
        }
        $refundStatus = $requestBody['Status'] ?? '';// 退款状态
        if ($refundStatus != 'SUCCESS') {
            Log::info('网商银行账户-退款状态失败：', ['requestBody' => $requestBody]);
            return [ResponseAlias::HTTP_OK, []];
        }
        $outRefundNo = $requestBody['OutRefundNo'] ?? '';// 外部退款交易号
        if ($outRefundNo) {
            $payStream = PayStreamModel::suffix(null)->where('payNo', $outRefundNo)->first();
            if ($payStream && $payStream->payChannel == PayStreamModel::PAY_CHANNEL_MYBANK_CASHIER_PAY) {// 网商 收银台支付
                MybankCashierOrderService::refundOrderNotify($requestBody, $payStream);
                return [ResponseAlias::HTTP_OK, []];
            }
        }
        $mybankVostroBillModel = MybankVostroBillModel::query()
                                                      ->where('orderNo', $requestBody['RefundOrderNo'])
                                                      ->first();
        if ($mybankVostroBillModel) {//通过订单号查询当前记录是否新增过
            return [ResponseAlias::HTTP_OK, []];
        }

        $amount       = $requestBody['RefundAmount'] ?? 0;
        $amount       = bcdiv100($amount);
        $transferDate = strtotime($requestBody['RefundFinishDate']);
        if ($requestBody['ParticipantType'] != MybankVostroBillModel::MERCHANT_PARTICIPANT_TYPE) {//商户(MERCHANT)、 平台(PLATFORM)、 保证金账号(PLATFOSUBACCOUNTRM)
            $type       = MybankVostroBillModel::MAPPING_PARTICIPANT_TYPE[$requestBody['ParticipantType']];
            $finishDate = date('Y-m-d H:i:s', $transferDate);
            $content    = <<<STR
        退款参与方类型: {$type}
        退款参与方id: {$requestBody['ParticipantId']}
        金额: {$amount}
        完成时间: {$finishDate}
        状态: {$requestBody['Status']}

        STR;
            $title      = '网商银行账户-充值退款结果通知接口返回非商户类型';
            Log::info('网商银行账户-充值退款结果通知接口返回非商户类型：', ['requestBody' => $requestBody]);
            if ($requestBody['RelateOrderNo'] && $requestBody['RelateTransNo']) {
                //查询原充值订单信息
                $mybankVostroBillModel = MybankVostroBillModel::query()
                                                              ->where('orderNo', $requestBody['RelateOrderNo'])
                                                              ->where('transNo', $requestBody['RelateTransNo'])
                                                              ->first();
                if (!$mybankVostroBillModel) {
                    self::sendFs($title, $content);
                    return [ResponseAlias::HTTP_OK, []];
                }
                $merchantId = $mybankVostroBillModel->merchantId ?? "";//原充值订单的商户号
            } else {
                self::sendFs($title, $content);
                return [ResponseAlias::HTTP_OK, []];
            }
        } else {
            $merchantId = $requestBody['ParticipantId'] ?? "";
        }
        $data               = [
            'isvOrgId'                      => $requestBody['IsvOrgId'],
            //合作方机构号（网商银行分配）
            'merchantId'                    => $merchantId,
            //退款参与方id 如果是商户，则填入merchantId,如果是平台，则填入isvOrgId
            'outTradeNo'                    => $requestBody['OutRefundNo'],
            //退款交易号
            'orderNo'                       => $requestBody['RefundOrderNo'],
            //退款网商订单号
            'transNo'                       => $requestBody['TransNo'] ?? "",
            //入账流水号
            'channelId'                     => $requestBody['ChannelId'] ?? "",
            //出款渠道id（9001大额、9002小额、9003超网、9100支付宝）
            'payerBankId'                   => $requestBody['PayerBankId'] ?? "",
            //付款方银行编码
            'payerCardNo'                   => $requestBody['PayerCardNo'] ?? "",
            //付款方卡号
            'payerCardName'                 => $requestBody['PayerCardName'] ?? "",
            //付款方卡号户名
            'payeeCardNo'                   => $requestBody['BankCardNo'] ?? "",
            //绑定银行卡号
            'payeeCardName'                 => $requestBody['BankCertName'] ?? "",
            //绑定卡号户名
            'vostroScene'                   => $requestBody['VostroScene'] ?? "",
            //来账场景
            'amount'                        => $requestBody['RefundAmount'],
            //订单金额(金额为分)
            'transferDate'                  => $transferDate,
            //完成时间
            'currency'                      => $requestBody['Currency'],
            //币种，默认CNY
            'memo'                          => $requestBody['Memo'] ?? "",
            //备注
            'extInfo'                       => $requestBody['ExtInfo'] && !empty($requestBody['ExtInfo']) ? base64_decode($requestBody['ExtInfo']) : "",
            //扩展信息
            'status'                        => $requestBody['Status'],
            //状态
            'remark'                        => $requestBody['Scene'] ?? "",
            //转账附言
            'type'                          => MybankVostroBillModel::RECHARGE_REFUND_TYPE,
            //充值退款
            'relateOrderNo'                 => $requestBody['RelateOrderNo'] ?? "",
            //关联网商订单号
            'relateTransNo'                 => $requestBody['RelateTransNo'] ?? "",
            //关联网商支付流水号
            'participantActualRefundAmount' => $requestBody['ParticipantActualRefundAmount'] ?? 0,
            //商户实际退款金额
            'participantType'               => $requestBody['ParticipantType'] ?? "",
            //退款参与方类型 商户(MERCHANT)、 平台(PLATFORM)、 保证金账号(SUBACCOUNT)
            'participantId'                 => $requestBody['ParticipantId'] ?? "",
            //退款参与方id 如果是商户，则填入merchantId,如果是平台，则填入isvOrgId,当ParticipantType为SUBACCOUNT（保证金账号）时ParticipantId为保证金的账号
        ];
        $res                = MybankVostroBillModel::addData($data);
        $id                 = $res ? $res->id : 0;
        $withdrawFinishDate = date('Y-m-d H:i:s', $transferDate);
        $content            = <<<STR
        商户号: {$data['merchantId']}
        金额: {$amount}
        完成时间: {$withdrawFinishDate}
        状态: {$requestBody['Status']}

        STR;
        if (!$id) {
            $title = '网商银行账户-充值退款结果通知接口数据插入失败';
            self::sendFs($title, $content);
            Log::info('网商银行账户-充值退款结果通知接口数据插入失败：', ['requestBody' => $requestBody]);
            return [ResponseAlias::HTTP_OK, []];
        }

        // 获取余额
        $balanceInfo   = self::getMerchantBalance($data['merchantId']);
        $balanceFreeze = $balanceInfo['BALANCE_FREEZE'] ?? 0;
        $balancePAY    = $balanceInfo['PAY'] ?? 0;


        // 钱包添加记录
        MybankOrderWithholdService::walletRecordAdd(
            $data['merchantId'],
            MybankWalletRecordModel::INCOME_TRANS_TYPE,
            $requestBody['RefundAmount'],
            (int)bcadd($balanceFreeze, $balancePAY),
            0,
            $id,
            MybankWalletRecordModel::RECORD_ID_TYPE_VOSTRO_BILL,
            MybankWalletRecordModel::PLATFORM_TYPE_MYBANK,
            "商户提现", $data['orderNo'], $data['memo'], $transferDate,
            MybankWalletRecordModel::SUCCESS_STATUS,
            MybankWalletRecordModel::SHOW_RECORD
        );

        $title = '网商银行账户-充值退款结果通知接口成功';
        self::sendFs($title, $content);
        Log::info('网商银行账户-充值退款结果通知接口end：', ['requestBody' => $requestBody, 'id' => $id]);
        return [ResponseAlias::HTTP_OK, []];
    }

    /**
     * 更新批处理的账单周期时间
     *
     * @param int $id
     * @param int $startAt
     * @param int $endAt
     * @return int
     */
    public static function updateBillRecordBindBillDate(int $id, int $startAt, int $endAt): int
    {
        return MybankBillRecordBindModel::query()->where('id', $id)->update([
            'billStartAt' => $startAt,
            'billEndAt'   => $endAt
        ]);
    }

    /**
     * 批次不同平台记录-redis
     * @param $platform
     * @param int $isGet
     * @return mixed
     */
    public static function platformCacheMark($platform, $isGet = 0)
    {
        $key = sprintf('mybank:' . '%s:%s', date('Ymd'), $platform);
        if ($isGet) {
            return Redis::get($key);
        } else {
            $res = Redis::incr($key, 1);
            if ($res == 1) {
                Redis::expire($key, strtotime(date('Y-m-d', strtotime('+1 day'))) - time());
            }
            return $res;
        }

    }

    /**
     * 根据网商打款记录匹配对应三方账单记录（金额可能是多个门店记录相加）
     *
     * @param $date
     * @param $time
     * @param $source
     * @return array
     * @throws BaseException
     * @throws GuzzleException
     */
    public static function matchBillRecordByDate($date, $time, $source): array
    {
        $res        = ['code' => 500, 'msg' => '账单未匹配完成'];
        $sourceText = MybankBillRecordModel::MAPPING_SOURCE[$source] ?? "";
        MybankVostroBillModel::query()
                             ->where('type', 0)
                             ->where(function ($query) use ($source) {
                                 switch ($source) {
                                     case MybankBillRecordModel::SOURCE_CANTEEN:
                                         $query->where('payerCardName', 'like', '%富友%');
                                         break;
                                 }
                             })
                             ->where('flagMark', MybankVostroBillModel::DEFAULT_FLAG_MARK)
                             ->orderBy('id')
                             ->chunk(10, function ($vostroBillList) use ($sourceText, $date, $time, $source, &$res) {
                                 foreach ($vostroBillList as $vostroBill) {

                                     $startDay  = date('Y-m-d', $vostroBill['transferDate']);
                                     $startDate = strtotime($startDay);

                                     $totalTransAmount = MybankBillRecordModel::getBillRecordTotalAmount(
                                         0, MybankBillRecordModel::WITHDRAW_TRANS_TYPE,
                                         MybankBillRecordModel::DEFAULT_FLAG_MARK,
                                         $source, $startDate, $startDate + 86399);

                                     if ($totalTransAmount != $vostroBill['amount']) {// 账单记录不匹配网商打款金额
                                         Log::channel('mybank')
                                            ->notice($sourceText . '分账数据-账单记录不匹配网商打款金额', [
                                                'startDay'         => $startDay,
                                                'totalTransAmount' => $totalTransAmount,
                                                'vostroBillAmount' => $vostroBill['amount'],
                                            ]);
                                         continue;
                                     }

                                     // 1.查询对应账单记录
                                     $billRecordList = MybankBillRecordModel::getBillRecordList(
                                         0, MybankBillRecordModel::WITHDRAW_TRANS_TYPE,
                                         MybankBillRecordModel::DEFAULT_FLAG_MARK, 0,
                                         $source, $startDate, $startDate + 86399);

                                     $totalAmount  = 0;
                                     $relationData = $data = [];

                                     if ($billRecordList) {
                                         foreach ($billRecordList as $billRecord) {
                                             $getMerchantInfo = self::getMerchantIdByShopId($billRecord['shopId']);
                                             if (!$getMerchantInfo['merchantId']) { // 排除无商户id
                                                 Log::channel('mybank')
                                                    ->notice($sourceText . '分账数据-排除无商户id记录', [
                                                        'shopId'       => $billRecord['shopId'],
                                                        'fsNotifyUids' => [
                                                            '3fgc8798',
                                                        ]
                                                    ]);
                                                 continue;
                                             }
                                             $totalAmount    += $billRecord['transAmount'];
                                             $data[]         = array_merge($billRecord, [
                                                 'entryId'      => $getMerchantInfo['entryId'],
                                                 'merchantId'   => $getMerchantInfo['merchantId'],
                                                 'merchantName' => $getMerchantInfo['merchantName']
                                             ]);
                                             $relationData[] = [
                                                 'vostroBillId' => $vostroBill['id'],
                                                 'billRecordId' => $billRecord['id'],
                                                 'merchantId'   => $getMerchantInfo['merchantId'],
                                             ];
                                         }
                                     }


                                     $amountVostro = bcdiv100($vostroBill['amount']);

                                     if (!($totalAmount == $vostroBill['amount'] && $data && $relationData)) {
                                         Log::channel('mybank')->notice($sourceText . '分账数据-金额未匹配', [
                                             'totalAmount'      => $totalAmount,
                                             'mybankVostroBill' => $vostroBill['amount'],
                                             'emptyData'        => empty($data),
                                             'relationData'     => empty($relationData)
                                         ]);
                                         continue;
                                     }

                                     $fuyouBillRecordDates = [];
                                     //查询堂食订单
                                     if ($source == MybankBillRecordModel::SOURCE_CANTEEN) {
                                         $fuyouBillRecordDates = self::matchFuyouBillRecordByDate($data);

                                         if (!$fuyouBillRecordDates) {
                                             Log::channel('mybank')
                                                ->notice($sourceText . '分账数据-查询堂食订单未匹配', [
                                                    'amountVostro' => $amountVostro,
                                                ]);
                                             $res = ['code' => 500, 'msg' => '查询堂食订单未匹配'];
                                             break;
                                         }
                                         $transactionAmountTotal = array_sum(array_column($fuyouBillRecordDates,
                                             'transactionAmount'));
                                         $transactionFeeTotal    = array_sum(array_column($fuyouBillRecordDates,
                                             'transactionFee'));


                                         if ($totalAmount != $transactionAmountTotal - $transactionFeeTotal) {
                                             Log::channel('mybank')
                                                ->notice($sourceText . '分账数据-查询堂食订单金额未匹配', [
                                                    'totalAmount'  => $totalAmount,
                                                    'actualAmount' => $transactionAmountTotal - $transactionFeeTotal,
                                                ]);
                                             $res = ['code' => 500, 'msg' => '查询堂食订单金额未匹配'];
                                             break;
                                         }
                                     }
                                     $acquireId = 'DEFAULT';//门店自主收银模式下，填写对应的渠道编号，对接时找技术同学确认；
                                     //批次号
                                     $batchNo = date('Ymd') . "_" . str_pad(self::autoincrementByRedis('batchNo'),
                                             2, "0", STR_PAD_LEFT);
                                     list($totalAmount, $data) = MybankBatchService::dealBatchMinusAmount($data);

                                     //3.文件上传
                                     MybankCreateBatchRemote::batchFileUpload($acquireId, $batchNo, $date, "",
                                         $data, $source, $fuyouBillRecordDates);

                                     //4.创建结算批次
                                     $resultJson = MybankCreateBatchRemote::batchCreate($batchNo, $source);
                                     $body       = $resultJson["response"]["body"];
                                     if ($body['RespInfo']['ResultCode'] != '0000') {
                                         Log::channel('mybank')->error($sourceText . '分账数据-创建结算批次失败', [
                                             'resBody'      => $body,
                                             'batchNo'      => $batchNo,
                                             'fsNotifyUids' => [
                                                 '346gc6ea',
                                             ]
                                         ]);
                                         $res = ['code' => 500, 'msg' => '账单匹配未完成,创建结算批次失败'];
                                         break;
                                     }

                                     $batchInstanceId = $body['BatchInstanceId'] ?? '';//批次实例号，由本次批次处理的id号
                                     $acquireId       = $body['AcquireId'] ?? '';//渠道编号


                                     $res = self::matchBillRecordHandle($relationData,
                                         $batchNo,
                                         $batchInstanceId,
                                         $acquireId,
                                         $time,
                                         $sourceText,
                                         $amountVostro);
                                     break;
                                 }

                                 // 匹配成功等网商返回再处理下一个
                                 if ($res) {
                                     return $res;
                                 }
                             });

        return $res;
    }


    /**
     * 堂食订单匹配
     *
     * @param array $data 数据
     * @param bool $isSplitOut 是否需要拆分输出
     * @return array
     */
    public static function matchFuyouBillRecordByDate(array $data, bool $isSplitOut = false): array
    {
        $fuyouBillRecordDates = [];
        $shopDateData         = [];

        foreach ($data as $billRecord) {
            // 查询上一次提现到本次提现中间 结算 账单日期
            $transactionDates = [];
            $lastWithdraw     = MybankBillRecordModel::query()
                                                     ->where('shopId', $billRecord['shopId'])
                                                     ->where('transDate', '<', $billRecord['billDate'])
                                                     ->where('source', MybankBillRecordModel::SOURCE_CANTEEN)
                                                     ->where('transType', MybankBillRecordModel::WITHDRAW_TRANS_TYPE)
                                                     ->orderByDesc('id')
                                                     ->first();

            $transactionDates = MybankBillRecordModel::query()
                                                     ->where('shopId', $billRecord['shopId'])
                                                     ->where('transDate', '<', $billRecord['billDate'])
                                                     ->when(!empty($lastWithdraw),
                                                         function ($query) use ($lastWithdraw) {
                                                             $query->where('transDate', '>=',
                                                                 $lastWithdraw['billDate']);
                                                         })
                                                     ->where('source', MybankBillRecordModel::SOURCE_CANTEEN)
                                                     ->where('transType', MybankBillRecordModel::INCOME_TRANS_TYPE)
                                                     ->orderByDesc('id')
                                                     ->get()
                                                     ->pluck('billDate')
                                                     ->map(function ($item) {
                                                         return date('Ymd', $item);
                                                     });


            $fuyouBillRecordDate = MybankFuyouBillRecordModel::query()
                                                             ->where('shopId', $billRecord['shopId'])
                                                             ->where('mybankMerchantId', $billRecord['merchantId'])
                                                             ->whereIn('transactionDate', $transactionDates)
                                                             ->where('mybankOrderNo', '!=', 0)
                                                             ->where('transactionAmount', '>', 0)
                                                             ->get()
                                                             ->toArray();

            if (!$fuyouBillRecordDate) {
                continue;
            }

            // 查询退款订单
            $fuyouBillRecordArr = [];
            MybankFuyouBillRecordModel::query()
                                      ->where('shopId', $billRecord['shopId'])
                                      ->where('mybankMerchantId', $billRecord['merchantId'])
                                      ->whereIn('transactionDate', $transactionDates)
                                      ->where('transactionAmount', '<', 0)
                                      ->get()
                                      ->map(function ($item) use (&$fuyouBillRecordArr) {
                                          if (isset($fuyouBillRecordArr[$item['originalTransactionOrderNo']])) {
                                              $fuyouBillRecordArr[$item['originalTransactionOrderNo']]['transactionAmount'] += $item['transactionAmount'];
                                              $fuyouBillRecordArr[$item['originalTransactionOrderNo']]['transactionFee']    += $item['transactionFee'];
                                          } else {
                                              $fuyouBillRecordArr[$item['originalTransactionOrderNo']] = $item->toArray();
                                          }
                                      });
            if ($fuyouBillRecordArr) {
                foreach ($fuyouBillRecordDate as $k => &$v) {
                    $fuyouBillRecordRefundData = $fuyouBillRecordArr[$v['merchantOrderNo']] ?? [];//通过退款 原交易订单号 匹配 商户订单号
                    if ($fuyouBillRecordRefundData) {
                        if (($v['transactionAmount'] + $fuyouBillRecordRefundData['transactionAmount']) <= 0) {//判断是否全部退款
                            unset($fuyouBillRecordDate[$k]);
                        } else {
                            $v['transactionAmount'] = $v['transactionAmount'] + $fuyouBillRecordRefundData['transactionAmount'];
                            $v['transactionFee']    = ($v['transactionFee'] + $fuyouBillRecordRefundData['transactionFee']) > 0 ? $v['transactionFee'] + $fuyouBillRecordRefundData['transactionFee'] : 0;
                        }
                    }
                }
            }
            if (!$fuyouBillRecordDate) {
                continue;
            }
            $shopDateData[$billRecord['shopId']] = $fuyouBillRecordDate;

            $fuyouBillRecordDates = array_merge($fuyouBillRecordDates, $fuyouBillRecordDate);
        }

        if ($isSplitOut) {
            return $shopDateData;
        } else {
            return $fuyouBillRecordDates;
        }
    }


    /**
     * 匹配完成之后数据库处理
     * @param $relationData
     * @param $batchNo
     * @param $batchInstanceId
     * @param $acquireId
     * @param $time
     * @param $sourceText
     * @param $amountVostro
     * @return array
     */
    public static function matchBillRecordHandle(
        $relationData,
        $batchNo,
        $batchInstanceId,
        $acquireId,
        $time,
        $sourceText,
        $amountVostro
    ): array {

        DB::beginTransaction();
        try {

            // 绑定网商银行账单记录和外卖平台提现记录
            collect($relationData)->chunk(500)->each(function ($item) use (
                $batchNo,
                $batchInstanceId,
                $acquireId,
                $time
            ) {
                $createData = $item->map(function ($data) use ($batchNo, $time, $acquireId, $batchInstanceId) {
                    return [
                        'billRecordId'    => $data['billRecordId'],//外卖平台账单记录 ID
                        'vostroBillId'    => $data['vostroBillId'],//网商银行来账记录 ID
                        'batchNo'         => $batchNo,//批次号
                        'batchInstanceId' => $batchInstanceId,//批次实例号，由本次批次处理的id号
                        'acquireId'       => $acquireId,//渠道编号
                        'merchantId'      => $data['merchantId'],//网商的商户号
                        'createdAt'       => $time,
                    ];
                })->toArray();

                // 网商银行来账记录与外卖平台账单记录关联绑定
                MybankBillRecordBindModel::query()->insert($createData);
                $vostroBillIds = $item->pluck('vostroBillId')->toArray();
                $billRecordIds = $item->pluck('billRecordId')->toArray();
                if ($vostroBillIds) {//网商银行账户明细
                    MybankVostroBillModel::query()
                                         ->whereIn('id', $vostroBillIds)
                                         ->where('flagMark',
                                             MybankVostroBillModel::DEFAULT_FLAG_MARK)
                                         ->update(['flagMark' => MybankVostroBillModel::MATCH_FLAG_MARK]);
                }
                if ($billRecordIds) {//账单记录管理
                    MybankBillRecordModel::query()
                                         ->whereIn('id', $billRecordIds)
                                         ->where('flagMark',
                                             MybankBillRecordModel::DEFAULT_FLAG_MARK)
                                         ->update(['flagMark' => MybankBillRecordModel::MATCH_FLAG_MARK]);
                }
            });
            DB::commit();
        } catch (\Exception $e) {
            DB::rollBack();

            Log::channel('mybank')->error($sourceText . '分账数据-批次创建sql失败', [
                'msg'          => $e->getMessage(),
                'batchNo'      => $batchNo,
                'fsNotifyUids' => [
                    '346gc6ea',
                ]
            ]);
            return ['code' => 500, 'msg' => '批次创建sql失败'];
        }
        Log::channel('mybank')->notice($sourceText . '分账数据-批次创建成功', [
            'batchNo'         => $batchNo,//批次号
            'amountVostro'    => $amountVostro,//匹配金额
            'batchInstanceId' => $batchInstanceId,//批次实例号
            'acquireId'       => $acquireId,//渠道编号
        ]);
        return ['code' => 200, 'msg' => '创建成功'];
    }
}
